guests/windows: configure networks
This commit is contained in:
parent
d86a9ecade
commit
d600e83e6d
|
@ -1,10 +1,6 @@
|
||||||
require "log4r"
|
require "log4r"
|
||||||
|
|
||||||
require_relative '../../communication/guestnetwork'
|
require_relative "../guest_network"
|
||||||
require_relative '../../communication/winrmshell'
|
|
||||||
require_relative '../../errors'
|
|
||||||
require_relative '../../helper'
|
|
||||||
require_relative '../../windows_machine'
|
|
||||||
|
|
||||||
module VagrantPlugins
|
module VagrantPlugins
|
||||||
module GuestWindows
|
module GuestWindows
|
||||||
|
@ -15,19 +11,20 @@ module VagrantPlugins
|
||||||
def self.configure_networks(machine, networks)
|
def self.configure_networks(machine, networks)
|
||||||
@@logger.debug("Networks: #{networks.inspect}")
|
@@logger.debug("Networks: #{networks.inspect}")
|
||||||
|
|
||||||
windows_machine = VagrantWindows::WindowsMachine.new(machine)
|
guest_network = GuestNetwork.new(machine.communicate.shell)
|
||||||
guest_network = VagrantWindows::Communication::GuestNetwork.new(windows_machine.winrmshell)
|
if machine.provider_name.to_s.start_with?("vmware")
|
||||||
if windows_machine.is_vmware?()
|
machine.ui.warn("Configuring secondary network adapters through VMware ")
|
||||||
@@logger.warn('Configuring secondary network adapters through VMware is not yet supported.')
|
machine.ui.warn("on Windows is not yet supported. You will need to manually")
|
||||||
@@logger.warn('You will need to manually configure the network adapter.')
|
machine.ui.warn("configure the network adapter.")
|
||||||
else
|
else
|
||||||
vm_interface_map = create_vm_interface_map(windows_machine, guest_network)
|
vm_interface_map = create_vm_interface_map(machine, guest_network)
|
||||||
networks.each do |network|
|
networks.each do |network|
|
||||||
interface = vm_interface_map[network[:interface]+1]
|
interface = vm_interface_map[network[:interface]+1]
|
||||||
if interface.nil?
|
if interface.nil?
|
||||||
@@logger.warn("Could not find interface for network #{network.inspect}")
|
@@logger.warn("Could not find interface for network #{network.inspect}")
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
network_type = network[:type].to_sym
|
network_type = network[:type].to_sym
|
||||||
if network_type == :static
|
if network_type == :static
|
||||||
guest_network.configure_static_interface(
|
guest_network.configure_static_interface(
|
||||||
|
@ -40,19 +37,27 @@ module VagrantPlugins
|
||||||
interface[:index],
|
interface[:index],
|
||||||
interface[:net_connection_id])
|
interface[:net_connection_id])
|
||||||
else
|
else
|
||||||
raise WindowsError, "#{network_type} network type is not supported, try static or dhcp"
|
raise "#{network_type} network type is not supported, try static or dhcp"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
guest_network.set_all_networks_to_work() if windows_machine.windows_config.set_work_network
|
|
||||||
end
|
|
||||||
|
|
||||||
#{1=>{:name=>"Local Area Connection", :mac_address=>"0800275FAC5B", :interface_index=>"11", :index=>"7"}}
|
if machine.config.windows.set_work_network
|
||||||
def self.create_vm_interface_map(windows_machine, guest_network)
|
guest_network.set_all_networks_to_work
|
||||||
vm_interface_map = {}
|
end
|
||||||
driver_mac_address = windows_machine.read_mac_addresses.invert
|
end
|
||||||
|
|
||||||
|
def self.create_vm_interface_map(machine, guest_network)
|
||||||
|
if !machine.provider.capability?(:nic_mac_addresses)
|
||||||
|
raise Errors::CantReadMACAddresses,
|
||||||
|
provider: machine.provider_name.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
driver_mac_address = machine.provider.capability(:nic_mac_addresses)
|
||||||
@@logger.debug("mac addresses: #{driver_mac_address.inspect}")
|
@@logger.debug("mac addresses: #{driver_mac_address.inspect}")
|
||||||
guest_network.network_adapters().each do |nic|
|
|
||||||
|
vm_interface_map = {}
|
||||||
|
guest_network.network_adapters.each do |nic|
|
||||||
@@logger.debug("nic: #{nic.inspect}")
|
@@logger.debug("nic: #{nic.inspect}")
|
||||||
naked_mac = nic[:mac_address].gsub(':','')
|
naked_mac = nic[:mac_address].gsub(':','')
|
||||||
if driver_mac_address[naked_mac]
|
if driver_mac_address[naked_mac]
|
||||||
|
@ -63,6 +68,7 @@ module VagrantPlugins
|
||||||
:index => nic[:index] }
|
:index => nic[:index] }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@logger.debug("vm_interface_map: #{vm_interface_map.inspect}")
|
@@logger.debug("vm_interface_map: #{vm_interface_map.inspect}")
|
||||||
vm_interface_map
|
vm_interface_map
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module GuestWindows
|
||||||
|
module Errors
|
||||||
|
# A convenient superclass for all our errors.
|
||||||
|
class WindowsError < Vagrant::Errors::VagrantError
|
||||||
|
error_namespace("vagrant_windows.errors")
|
||||||
|
end
|
||||||
|
|
||||||
|
class CantReadMACAddresses < WindowsError
|
||||||
|
error_key(:cant_read_mac_addresses)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,125 @@
|
||||||
|
require "log4r"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module GuestWindows
|
||||||
|
# Manages the remote Windows guest network.
|
||||||
|
class GuestNetwork
|
||||||
|
PS_GET_WSMAN_VER = '((test-wsman).productversion.split(" ") | select -last 1).split("\.")[0]'
|
||||||
|
WQL_NET_ADAPTERS_V2 = 'SELECT * FROM Win32_NetworkAdapter WHERE MACAddress IS NOT NULL'
|
||||||
|
|
||||||
|
def initialize(winrmshell)
|
||||||
|
@logger = Log4r::Logger.new("vagrant::windows::guestnetwork")
|
||||||
|
@winrmshell = winrmshell
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns an array of all NICs on the guest. Each array entry is a
|
||||||
|
# Hash of the NICs properties.
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
def network_adapters
|
||||||
|
wsman_version == 2? network_adapters_v2_winrm : network_adapters_v3_winrm
|
||||||
|
end
|
||||||
|
|
||||||
|
# Checks to see if the specified NIC is currently configured for DHCP.
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
def is_dhcp_enabled(nic_index)
|
||||||
|
has_dhcp_enabled = false
|
||||||
|
cmd = "Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter \"Index=#{nic_index} and DHCPEnabled=True\""
|
||||||
|
@winrmshell.powershell(cmd) do |type, line|
|
||||||
|
has_dhcp_enabled = !line.nil?
|
||||||
|
end
|
||||||
|
@logger.debug("NIC #{nic_index} has DHCP enabled: #{has_dhcp_enabled}")
|
||||||
|
has_dhcp_enabled
|
||||||
|
end
|
||||||
|
|
||||||
|
# Configures the specified interface for DHCP
|
||||||
|
#
|
||||||
|
# @param [Integer] The interface index.
|
||||||
|
# @param [String] The unique name of the NIC, such as 'Local Area Connection'.
|
||||||
|
def configure_dhcp_interface(nic_index, net_connection_id)
|
||||||
|
@logger.info("Configuring NIC #{net_connection_id} for DHCP")
|
||||||
|
if !is_dhcp_enabled(nic_index)
|
||||||
|
netsh = "netsh interface ip set address \"#{net_connection_id}\" dhcp"
|
||||||
|
@winrmshell.powershell(netsh)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Configures the specified interface using a static address
|
||||||
|
#
|
||||||
|
# @param [Integer] The interface index.
|
||||||
|
# @param [String] The unique name of the NIC, such as 'Local Area Connection'.
|
||||||
|
# @param [String] The static IP address to assign to the specified NIC.
|
||||||
|
# @param [String] The network mask to use with the static IP.
|
||||||
|
def configure_static_interface(nic_index, net_connection_id, ip, netmask)
|
||||||
|
@logger.info("Configuring NIC #{net_connection_id} using static ip #{ip}")
|
||||||
|
#netsh interface ip set address "Local Area Connection 2" static 192.168.33.10 255.255.255.0
|
||||||
|
netsh = "netsh interface ip set address \"#{net_connection_id}\" static #{ip} #{netmask}"
|
||||||
|
@winrmshell.powershell(netsh)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Sets all networks on the guest to 'Work Network' mode. This is
|
||||||
|
# to allow guest access from the host via a private IP on Win7
|
||||||
|
# https://github.com/WinRb/vagrant-windows/issues/63
|
||||||
|
def set_all_networks_to_work
|
||||||
|
@logger.info("Setting all networks to 'Work Network'")
|
||||||
|
command = File.read(File.expand_path("../scripts/set_work_network.ps1"))
|
||||||
|
@winrmshell.powershell(command)
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
# Checks the WinRS version on the guest. Usually 2 on Windows 7/2008
|
||||||
|
# and 3 on Windows 8/2012.
|
||||||
|
#
|
||||||
|
# @return [Integer]
|
||||||
|
def wsman_version
|
||||||
|
@logger.debug("querying WSMan version")
|
||||||
|
version = ''
|
||||||
|
@winrmshell.powershell(PS_GET_WSMAN_VER) do |type, line|
|
||||||
|
version = version + "#{line}" if type == :stdout && !line.nil?
|
||||||
|
end
|
||||||
|
@logger.debug("wsman version: #{version}")
|
||||||
|
Integer(version)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns an array of all NICs on the guest. Each array entry is a
|
||||||
|
# Hash of the NICs properties. This method should only be used on
|
||||||
|
# guests that have WinRS version 2.
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
def network_adapters_v2_winrm
|
||||||
|
@logger.debug("querying network adapters")
|
||||||
|
|
||||||
|
# Get all NICs that have a MAC address
|
||||||
|
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa394216(v=vs.85).aspx
|
||||||
|
adapters = @winrmshell.wql(WQL_NET_ADAPTERS_V2)[:win32_network_adapter]
|
||||||
|
@logger.debug("#{adapters.inspect}")
|
||||||
|
return adapters
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns an array of all NICs on the guest. Each array entry is a
|
||||||
|
# Hash of the NICs properties. This method should only be used on
|
||||||
|
# guests that have WinRS version 3.
|
||||||
|
#
|
||||||
|
# This method is a workaround until the WinRM gem supports WinRS version 3.
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
def network_adapters_v3_winrm
|
||||||
|
command = File.read(File.expand_path("../scripts/winrs_v3_get_adapters.ps1"))
|
||||||
|
output = ""
|
||||||
|
@winrmshell.powershell(command) do |type, line|
|
||||||
|
output = output + "#{line}" if type == :stdout && !line.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
adapters = []
|
||||||
|
JSON.parse(output).each do |nic|
|
||||||
|
adapters << nic.inject({}){ |memo,(k,v)| memo[k.to_sym] = v; memo }
|
||||||
|
end
|
||||||
|
|
||||||
|
@logger.debug("#{adapters.inspect}")
|
||||||
|
return adapters
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,6 +2,8 @@ require "vagrant"
|
||||||
|
|
||||||
module VagrantPlugins
|
module VagrantPlugins
|
||||||
module GuestWindows
|
module GuestWindows
|
||||||
|
autoload :Errors, File.expand_path("../errors", __FILE__)
|
||||||
|
|
||||||
class Plugin < Vagrant.plugin("2")
|
class Plugin < Vagrant.plugin("2")
|
||||||
name "Windows guest."
|
name "Windows guest."
|
||||||
description "Windows guest support."
|
description "Windows guest support."
|
||||||
|
@ -13,6 +15,7 @@ module VagrantPlugins
|
||||||
|
|
||||||
guest("windows") do
|
guest("windows") do
|
||||||
require_relative "guest"
|
require_relative "guest"
|
||||||
|
init!
|
||||||
Guest
|
Guest
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -45,6 +48,16 @@ module VagrantPlugins
|
||||||
require_relative "cap/mount_shared_folder"
|
require_relative "cap/mount_shared_folder"
|
||||||
Cap::MountSharedFolder
|
Cap::MountSharedFolder
|
||||||
end
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def self.init!
|
||||||
|
return if defined?(@_init)
|
||||||
|
I18n.load_path << File.expand_path(
|
||||||
|
"templates/locales/guest_windows.yml", Vagrant.source_root)
|
||||||
|
I18n.reload!
|
||||||
|
@_init = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
# Get network connections
|
||||||
|
$networkListManager = [Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]"{DCB00C01-570F-4A9B-8D69-199FDBA5723B}"))
|
||||||
|
$connections = $networkListManager.GetNetworkConnections()
|
||||||
|
|
||||||
|
# Set network location to Private for all networks
|
||||||
|
$connections | % {$_.GetNetwork().SetCategory(1)}
|
|
@ -0,0 +1,11 @@
|
||||||
|
$adapters = get-ciminstance win32_networkadapter -filter "macaddress is not null"
|
||||||
|
$processed = @()
|
||||||
|
foreach ($adapter in $adapters) {
|
||||||
|
$Processed += new-object PSObject -Property @{
|
||||||
|
mac_address = $adapter.macaddress
|
||||||
|
net_connection_id = $adapter.netconnectionid
|
||||||
|
interface_index = $adapter.interfaceindex
|
||||||
|
index = $adapter.index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
convertto-json -inputobject $processed
|
|
@ -15,6 +15,13 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Reads the network interface card MAC addresses and returns them.
|
||||||
|
#
|
||||||
|
# @return [Hash<String, String>] Adapter => MAC address
|
||||||
|
def self.nic_mac_addresses(machine)
|
||||||
|
machine.provider.driver.read_mac_addresses
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,6 +28,11 @@ module VagrantPlugins
|
||||||
require_relative "cap"
|
require_relative "cap"
|
||||||
Cap
|
Cap
|
||||||
end
|
end
|
||||||
|
|
||||||
|
provider_capability(:virtualbox, :nic_mac_addresses) do
|
||||||
|
require_relative "cap"
|
||||||
|
Cap
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
autoload :Action, File.expand_path("../action", __FILE__)
|
autoload :Action, File.expand_path("../action", __FILE__)
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
en:
|
||||||
|
vagrant_winrm:
|
||||||
|
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.
|
Loading…
Reference in New Issue