Merge pull request #6386 from legal90/fix-osx-nic-order
Fix network configuration in OS X (Darwin) guests
This commit is contained in:
commit
d69d7047b2
|
@ -240,6 +240,10 @@ module Vagrant
|
||||||
error_key(:bundler_error)
|
error_key(:bundler_error)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class CantReadMACAddresses < VagrantError
|
||||||
|
error_key(:cant_read_mac_addresses)
|
||||||
|
end
|
||||||
|
|
||||||
class CapabilityHostExplicitNotDetected < VagrantError
|
class CapabilityHostExplicitNotDetected < VagrantError
|
||||||
error_key(:capability_host_explicit_not_detected)
|
error_key(:capability_host_explicit_not_detected)
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,45 +6,109 @@ module VagrantPlugins
|
||||||
module GuestDarwin
|
module GuestDarwin
|
||||||
module Cap
|
module Cap
|
||||||
class ConfigureNetworks
|
class ConfigureNetworks
|
||||||
|
@@logger = Log4r::Logger.new("vagrant::guest::darwin::configure_networks")
|
||||||
|
|
||||||
include Vagrant::Util
|
include Vagrant::Util
|
||||||
|
|
||||||
def self.configure_networks(machine, networks)
|
def self.configure_networks(machine, networks)
|
||||||
# Slightly different than other plugins, using the template to build commands
|
if !machine.provider.capability?(:nic_mac_addresses)
|
||||||
# rather than templating the files.
|
raise Vagrant::Errors::CantReadMACAddresses,
|
||||||
|
provider: machine.provider_name.to_s
|
||||||
|
end
|
||||||
|
|
||||||
machine.communicate.sudo("networksetup -detectnewhardware")
|
nic_mac_addresses = machine.provider.capability(:nic_mac_addresses)
|
||||||
machine.communicate.sudo("networksetup -listnetworkserviceorder > /tmp/vagrant.interfaces")
|
@@logger.debug("mac addresses: #{nic_mac_addresses.inspect}")
|
||||||
tmpints = File.join(Dir.tmpdir, File.basename("#{machine.id}.interfaces"))
|
|
||||||
machine.communicate.download("/tmp/vagrant.interfaces",tmpints)
|
|
||||||
|
|
||||||
devlist = []
|
mac_service_map = create_mac_service_map(machine)
|
||||||
ints = ::IO.read(tmpints)
|
|
||||||
|
networks.each do |network|
|
||||||
|
mac_address = nic_mac_addresses[network[:interface]+1]
|
||||||
|
if mac_address.nil?
|
||||||
|
@@logger.warn("Could not find mac address for network #{network.inspect}")
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
service_name = mac_service_map[mac_address]
|
||||||
|
if service_name.nil?
|
||||||
|
@@logger.warn("Could not find network service for mac address #{mac_address}")
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
network_type = network[:type].to_sym
|
||||||
|
if network_type == :static
|
||||||
|
command = "networksetup -setmanual \"#{service_name}\" #{network[:ip]} #{network[:netmask]}"
|
||||||
|
elsif network_type == :dhcp
|
||||||
|
command = "networksetup -setdhcp \"#{service_name}\""
|
||||||
|
else
|
||||||
|
raise "#{network_type} network type is not supported, try static or dhcp"
|
||||||
|
end
|
||||||
|
|
||||||
|
machine.communicate.sudo(command)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a hash mapping MAC addresses to network service name
|
||||||
|
# Example: { "00C100A1B2C3" => "Thunderbolt Ethernet" }
|
||||||
|
def self.create_mac_service_map(machine)
|
||||||
|
tmp_ints = File.join(Dir.tmpdir, File.basename("#{machine.id}.interfaces"))
|
||||||
|
tmp_hw = File.join(Dir.tmpdir, File.basename("#{machine.id}.hardware"))
|
||||||
|
|
||||||
|
machine.communicate.tap do |comm|
|
||||||
|
comm.sudo("networksetup -detectnewhardware")
|
||||||
|
comm.sudo("networksetup -listnetworkserviceorder > /tmp/vagrant.interfaces")
|
||||||
|
comm.sudo("networksetup -listallhardwareports > /tmp/vagrant.hardware")
|
||||||
|
comm.download("/tmp/vagrant.interfaces", tmp_ints)
|
||||||
|
comm.download("/tmp/vagrant.hardware", tmp_hw)
|
||||||
|
end
|
||||||
|
|
||||||
|
interface_map = {}
|
||||||
|
ints = ::IO.read(tmp_ints)
|
||||||
ints.split(/\n\n/m).each do |i|
|
ints.split(/\n\n/m).each do |i|
|
||||||
if i.match(/Hardware/) and not i.match(/Ethernet/).nil?
|
if i.match(/Hardware/) && i.match(/Ethernet/)
|
||||||
devmap = {}
|
|
||||||
# Ethernet, should be 2 lines,
|
# Ethernet, should be 2 lines,
|
||||||
# (3) Thunderbolt Ethernet
|
# (3) Thunderbolt Ethernet
|
||||||
# (Hardware Port: Thunderbolt Ethernet, Device: en1)
|
# (Hardware Port: Thunderbolt Ethernet, Device: en1)
|
||||||
|
|
||||||
# multiline, should match "Thunderbolt Ethernet", "en1"
|
# multiline, should match "Thunderbolt Ethernet", "en1"
|
||||||
devicearry = i.match(/\([0-9]+\) (.+)\n.*Device: (.+)\)/m)
|
devicearry = i.match(/\([0-9]+\) (.+)\n.*Device: (.+)\)/m)
|
||||||
devmap[:interface] = devicearry[2]
|
service = devicearry[1]
|
||||||
devmap[:service] = devicearry[1]
|
interface = devicearry[2]
|
||||||
devlist << devmap
|
|
||||||
|
# Should map interface to service { "en1" => "Thunderbolt Ethernet" }
|
||||||
|
interface_map[interface] = service
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
File.delete(tmpints)
|
File.delete(tmp_ints)
|
||||||
|
|
||||||
networks.each do |network|
|
mac_service_map = {}
|
||||||
service_name = devlist[network[:interface]][:service]
|
macs = ::IO.read(tmp_hw)
|
||||||
if network[:type].to_sym == :static
|
macs.split(/\n\n/m).each do |i|
|
||||||
command = "networksetup -setmanual \"#{service_name}\" #{network[:ip]} #{network[:netmask]}"
|
if i.match(/Hardware/) && i.match(/Ethernet/)
|
||||||
elsif network[:type].to_sym == :dhcp
|
# Ethernet, should be 3 lines,
|
||||||
command = "networksetup -setdhcp \"#{service_name}\""
|
# Hardware Port: Thunderbolt 1
|
||||||
|
# Device: en1
|
||||||
|
# Ethernet Address: a1:b2:c3:d4:e5:f6
|
||||||
|
|
||||||
|
# multiline, should match "en1", "00:c1:00:a1:b2:c3"
|
||||||
|
devicearry = i.match(/Device: (.+)\nEthernet Address: (.+)/m)
|
||||||
|
interface = devicearry[1]
|
||||||
|
naked_mac = devicearry[2].gsub(':','').upcase
|
||||||
|
|
||||||
|
# Skip hardware ports without MAC (bridges, bluetooth, etc.)
|
||||||
|
next if naked_mac == "N/A"
|
||||||
|
|
||||||
|
if !interface_map[interface]
|
||||||
|
@@logger.warn("Could not find network service for interface #{interface}")
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
# Should map MAC to service, { "00C100A1B2C3" => "Thunderbolt Ethernet" }
|
||||||
|
mac_service_map[naked_mac] = interface_map[interface]
|
||||||
end
|
end
|
||||||
|
|
||||||
machine.communicate.sudo(command)
|
|
||||||
end
|
end
|
||||||
|
File.delete(tmp_hw)
|
||||||
|
|
||||||
|
mac_service_map
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -53,7 +53,7 @@ module VagrantPlugins
|
||||||
|
|
||||||
def self.create_vm_interface_map(machine, guest_network)
|
def self.create_vm_interface_map(machine, guest_network)
|
||||||
if !machine.provider.capability?(:nic_mac_addresses)
|
if !machine.provider.capability?(:nic_mac_addresses)
|
||||||
raise Errors::CantReadMACAddresses,
|
raise Vagrant::Errors::CantReadMACAddresses,
|
||||||
provider: machine.provider_name.to_s
|
provider: machine.provider_name.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,6 @@ module VagrantPlugins
|
||||||
error_namespace("vagrant_windows.errors")
|
error_namespace("vagrant_windows.errors")
|
||||||
end
|
end
|
||||||
|
|
||||||
class CantReadMACAddresses < WindowsError
|
|
||||||
error_key(:cant_read_mac_addresses)
|
|
||||||
end
|
|
||||||
|
|
||||||
class NetworkWinRMRequired < WindowsError
|
class NetworkWinRMRequired < WindowsError
|
||||||
error_key(:network_winrm_required)
|
error_key(:network_winrm_required)
|
||||||
end
|
end
|
||||||
|
|
|
@ -603,6 +603,14 @@ en:
|
||||||
issues. The error from Bundler is:
|
issues. The error from Bundler is:
|
||||||
|
|
||||||
%{message}
|
%{message}
|
||||||
|
cant_read_mac_addresses: |-
|
||||||
|
The provider you are using ('%{provider}') doesn't support the
|
||||||
|
"nic_mac_addresses" provider capability which is required
|
||||||
|
for advanced networking to work with this guest OS. Please inform
|
||||||
|
the author of the provider to add this feature.
|
||||||
|
|
||||||
|
Until then, you must remove any networking configurations other
|
||||||
|
than forwarded ports from your Vagrantfile for Vagrant to continue.
|
||||||
capability_host_explicit_not_detected: |-
|
capability_host_explicit_not_detected: |-
|
||||||
The explicit capability host specified of '%{value}' could not be
|
The explicit capability host specified of '%{value}' could not be
|
||||||
found.
|
found.
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
en:
|
en:
|
||||||
vagrant_windows:
|
vagrant_windows:
|
||||||
errors:
|
errors:
|
||||||
cant_read_mac_addresses: |-
|
|
||||||
The provider being used to start Windows ('%{provider}')
|
|
||||||
doesn't support the "nic_mac_addresses" capability which is required
|
|
||||||
for advanced networking to work with Windows guests. Please inform
|
|
||||||
the author of the provider to add this feature.
|
|
||||||
|
|
||||||
Until then, you must remove any networking configurations other
|
|
||||||
than forwarded ports from your Vagrantfile for Vagrant to continue.
|
|
||||||
network_winrm_required: |-
|
network_winrm_required: |-
|
||||||
Configuring networks on Windows requires the communicator to be
|
Configuring networks on Windows requires the communicator to be
|
||||||
set to WinRM. To do this, add the following to your Vagrantfile:
|
set to WinRM. To do this, add the following to your Vagrantfile:
|
||||||
|
|
Loading…
Reference in New Issue