diff --git a/lib/vagrant/action/vm/network.rb b/lib/vagrant/action/vm/network.rb index eba016ffe..9abf4c727 100644 --- a/lib/vagrant/action/vm/network.rb +++ b/lib/vagrant/action/vm/network.rb @@ -155,7 +155,14 @@ module Vagrant ip = args[0] options = args[1] || {} + # Determine if we're dealing with a static IP or a DHCP-served IP. + type = ip == :dhcp ? :dhcp : :static + + # Default IP is in the 20-bit private network block for DHCP based networks + ip = "172.28.128.1" if type == :dhcp + options = { + :type => type, :ip => ip, :netmask => "255.255.255.0", :adapter => nil, @@ -167,6 +174,34 @@ module Vagrant # bridged interfaces verify_no_bridge_collision(options) + # Get the network address and IP parts which are used for many + # default calculations + netaddr = network_address(options[:ip], options[:netmask]) + ip_parts = netaddr.split(".").map { |i| i.to_i } + + # Calculate the adapter IP, which we assume is the IP ".1" at the + # end usually. + adapter_ip = ip_parts.dup + adapter_ip[3] += 1 + options[:adapter_ip] ||= adapter_ip.join(".") + + if type == :dhcp + # Calculate the DHCP server IP, which is the network address + # with the final octet + 2. So "172.28.0.0" turns into "172.28.0.2" + dhcp_ip = ip_parts.dup + dhcp_ip[3] += 2 + options[:dhcp_ip] ||= dhcp_ip.join(".") + + # Calculate the lower and upper bound for the DHCP server + dhcp_lower = ip_parts.dup + dhcp_lower[3] += 3 + options[:dhcp_lower] ||= dhcp_lower.join(".") + + dhcp_upper = ip_parts.dup + dhcp_upper[3] = 254 + options[:dhcp_upper] ||= dhcp_upper.join(".") + end + # Return the hostonly network configuration return options end @@ -191,6 +226,15 @@ module Vagrant @logger.debug("Created network: #{interface[:name]}") end + if config[:type] == :dhcp + # TODO: Check that there isn't another DHCP server on this network + # that is different. + + # Configure the DHCP server for the network. + @logger.debug("Creating a DHCP server...") + @env[:vm].driver.create_dhcp_server(interface[:name], config) + end + return { :adapter => config[:adapter], :type => :hostonly, @@ -201,7 +245,7 @@ module Vagrant def hostonly_network_config(config) return { - :type => :static, + :type => config[:type], :ip => config[:ip], :netmask => config[:netmask] } @@ -210,18 +254,10 @@ module Vagrant # Creates a new hostonly network that matches the network requested # by the given host-only network configuration. def create_hostonly_network(config) - # First we need to determine a good IP for the host machine - # of this interface. We choose to use the network address - # plus 1, which is usually what is expected. - netaddr = network_address(config[:ip], config[:netmask]) - parts = netaddr.split(".").map { |i| i.to_i } - parts[3] += 1 - ip = parts.join(".") - # Create the options that are going to be used to create our # new network. options = config.dup - options[:ip] = ip + options[:ip] = options[:adapter_ip] @env[:vm].driver.create_host_only_network(options) end diff --git a/lib/vagrant/config/vm.rb b/lib/vagrant/config/vm.rb index 677c05d65..c3eae34b1 100644 --- a/lib/vagrant/config/vm.rb +++ b/lib/vagrant/config/vm.rb @@ -157,7 +157,9 @@ do before is certainly still possible with `VBoxManage` as well. # providers other than VirtualBox will not be able to satisfy # all types of networks. networks.each do |type, args| - if type == :hostonly + if type == :hostonly && args[0] == :dhcp + # Valid. There is no real way this can be invalid at the moment. + elsif type == :hostonly # Validate the host-only network ip = args[0] options = args[1] || {} diff --git a/lib/vagrant/driver/virtualbox.rb b/lib/vagrant/driver/virtualbox.rb index b28e189e1..23da30002 100644 --- a/lib/vagrant/driver/virtualbox.rb +++ b/lib/vagrant/driver/virtualbox.rb @@ -72,6 +72,7 @@ module Vagrant def_delegators :@driver, :clear_forwarded_ports, :clear_shared_folders, + :create_dhcp_server, :create_host_only_network, :delete, :delete_unused_host_only_networks, diff --git a/lib/vagrant/driver/virtualbox_4_0.rb b/lib/vagrant/driver/virtualbox_4_0.rb index cce816aea..c7060dd86 100644 --- a/lib/vagrant/driver/virtualbox_4_0.rb +++ b/lib/vagrant/driver/virtualbox_4_0.rb @@ -9,7 +9,7 @@ module Vagrant def initialize(uuid) super() - @logger = Log4r::Logger.new("vagrant::driver::virtualbox_4_0") + @logger = Log4r::Logger.new("vagrant::driver::virtualbox_4_1") @uuid = uuid end @@ -30,6 +30,15 @@ module Vagrant end end + def create_dhcp_server(network, options) + execute("dhcpserver", "add", "--ifname", network, + "--ip", options[:dhcp_ip], + "--netmask", options[:netmask], + "--lowerip", options[:dhcp_lower], + "--upperip", options[:dhcp_upper], + "--enable") + end + def create_host_only_network(options) # Create the interface execute("hostonlyif", "create") =~ /^Interface '(.+?)' was successfully created$/ @@ -37,13 +46,13 @@ module Vagrant # Configure it execute("hostonlyif", "ipconfig", name, - "--ip", options[:ip], + "--ip", options[:adapter_ip], "--netmask", options[:netmask]) # Return the details return { :name => name, - :ip => options[:ip], + :ip => options[:adapter_ip], :netmask => options[:netmask] } end @@ -69,6 +78,12 @@ module Vagrant end networks.each do |name| + # First try to remove any DHCP servers attached. We use `raw` because + # it is okay if this fails. It usually means that a DHCP server was + # never attached. + raw("dhcpserver", "remove", "--ifname", name) + + # Delete the actual host only network interface. execute("hostonlyif", "remove", name) end end diff --git a/lib/vagrant/driver/virtualbox_4_1.rb b/lib/vagrant/driver/virtualbox_4_1.rb index 7307cd83e..087667881 100644 --- a/lib/vagrant/driver/virtualbox_4_1.rb +++ b/lib/vagrant/driver/virtualbox_4_1.rb @@ -30,6 +30,15 @@ module Vagrant end end + def create_dhcp_server(network, options) + execute("dhcpserver", "add", "--ifname", network, + "--ip", options[:dhcp_ip], + "--netmask", options[:netmask], + "--lowerip", options[:dhcp_lower], + "--upperip", options[:dhcp_upper], + "--enable") + end + def create_host_only_network(options) # Create the interface execute("hostonlyif", "create") =~ /^Interface '(.+?)' was successfully created$/ @@ -37,13 +46,13 @@ module Vagrant # Configure it execute("hostonlyif", "ipconfig", name, - "--ip", options[:ip], + "--ip", options[:adapter_ip], "--netmask", options[:netmask]) # Return the details return { :name => name, - :ip => options[:ip], + :ip => options[:adapter_ip], :netmask => options[:netmask] } end @@ -69,6 +78,12 @@ module Vagrant end networks.each do |name| + # First try to remove any DHCP servers attached. We use `raw` because + # it is okay if this fails. It usually means that a DHCP server was + # never attached. + raw("dhcpserver", "remove", "--ifname", name) + + # Delete the actual host only network interface. execute("hostonlyif", "remove", name) end end diff --git a/lib/vagrant/driver/virtualbox_base.rb b/lib/vagrant/driver/virtualbox_base.rb index 3b1aa6ce9..bd52e4561 100644 --- a/lib/vagrant/driver/virtualbox_base.rb +++ b/lib/vagrant/driver/virtualbox_base.rb @@ -47,6 +47,13 @@ module Vagrant def clear_shared_folders end + # Creates a DHCP server for a host only network. + # + # @param [String] network Name of the host-only network. + # @param [Hash] options Options for the DHCP server. + def create_dhcp_server(network, options) + end + # Creates a host only network with the given options. # # @param [Hash] options Options to create the host only network.