Closed uchagani closed 1 year ago
To set the IP address for a private network, maybe this could help: http://professionalvmware.com/2008/12/vmware-vix-changing-ips-of-a-guest-vm/
vmrun -gu [Guest User] -gp [Guest Password] runProgramInGuest “[Path] to/the.vmx” c:\windows\system32\netsh int ip set address “Local Area Connection” static 192.168.15.25 255.255.255.0 192.168.15.1
@mitchellh I just made a test from my Mac spinning up a Windows 10 VM in VMware Fusion with an additional private network with a static ip 192.168.33.15
defined in the Vagrantfile
:
# -*- mode: ruby -*-
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "windows_10"
config.vm.network :forwarded_port, guest: 5985, host: 5985, id: "winrm", auto_correct: true
config.vm.network :forwarded_port, guest: 3389, host: 3389, id: "rdp", auto_correct: true
config.vm.network :private_network, ip: "192.168.33.15", gateway: "192.168.33.1"
config.vm.communicator = "winrm"
config.winrm.username = "vagrant"
config.winrm.password = "vagrant"
config.vm.guest = :windows
config.windows.halt_timeout = 15
["vmware_fusion", "vmware_workstation"].each do |provider|
config.vm.provider provider do |v, override|
v.gui = true
end
end
end
Spinning up the Vagrant VM shows the warning for that second network card:
$ vagrant up --provider vmware_fusion
Bringing machine 'default' up with 'vmware_fusion' provider...
==> default: Cloning VMware VM: 'windows_10'. This can take some time...
==> default: Verifying vmnet devices are healthy...
==> default: Preparing network adapters...
==> default: Starting the VMware VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: WinRM address: 192.168.254.134:5985
default: WinRM username: vagrant
default: WinRM transport: plaintext
==> default: Machine booted and ready!
==> default: Forwarding ports...
default: -- 3389 => 3389
default: -- 22 => 2222
default: -- 5985 => 5985
==> default: Configuring network adapters within the VM...
==> default: Configuring secondary network adapters through VMware
==> default: on Windows is not yet supported. You will need to manually
==> default: configure the network adapter.
==> default: Enabling and configuring shared folders...
default: -- /Users/stefan/code/win10: /vagrant
Inside the Windows 10 VM the network addresses are configured as follows:
C:\Users\vagrant>netsh int ip show addresses
Configuration for interface "Ethernet 3"
DHCP enabled: Yes
IP Address: 192.168.254.134
Subnet Prefix: 192.168.254.0/24 (mask 255.255.255.0)
Default Gateway: 192.168.254.2
Gateway Metric: 1
InterfaceMetric: 5
Configuration for interface "Ethernet 2"
DHCP enabled: Yes
IP Address: 192.168.33.129
Subnet Prefix: 192.168.33.0/24 (mask 255.255.255.0)
InterfaceMetric: 10
Configuration for interface "Loopback Pseudo-Interface 1"
DHCP enabled: No
IP Address: 127.0.0.1
Subnet Prefix: 127.0.0.0/8 (mask 255.0.0.0)
InterfaceMetric: 50
The second network has DHCP enabled and has to be changed to the fixed IP address given in the Vagrantfile
. I tried the vmrun
command like above to do this and run this command from my MBP:
$ "/Applications/VMware Fusion.app/Contents/Library/vmrun" -gu vagrant -gp vagrant runProgramInGuest .vagrant/machines/default/vmware_fusion/d254df82-2549-48df-a691-36b2c5f56598/packer-vmware-iso.vmx netsh.exe int ip set address "Ethernet 2" static 192.168.33.15 255.255.255.0 192.168.33.1
Afterwards the networks in the Windows 10 VM shows the correct settings:
C:\Users\vagrant>netsh int ip show addresses
Configuration for interface "Ethernet 3"
DHCP enabled: Yes
IP Address: 192.168.254.134
Subnet Prefix: 192.168.254.0/24 (mask 255.255.255.0)
Default Gateway: 192.168.254.2
Gateway Metric: 1
InterfaceMetric: 5
Configuration for interface "Ethernet 2"
DHCP enabled: No
IP Address: 192.168.33.15
Subnet Prefix: 192.168.33.0/24 (mask 255.255.255.0)
Default Gateway: 192.168.33.1
Gateway Metric: 1
InterfaceMetric: 10
Configuration for interface "Loopback Pseudo-Interface 1"
DHCP enabled: No
IP Address: 127.0.0.1
Subnet Prefix: 127.0.0.0/8 (mask 255.0.0.0)
InterfaceMetric: 50
The only difficulty with this approach is to get the interface name "Ethernet 2" from the host as it seems that vmrun doesn't show the stdout of the program in the VM.
But this could also be done with the winrm communicator to run the netsh.exe int ip addresses
command.
I've tried it in a small provision script and came up to this workaround:
# -*- mode: ruby -*-
# vi: set ft=ruby :
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = "windows_10"
config.vm.network :forwarded_port, guest: 5985, host: 5985, id: "winrm", auto_correct: true
config.vm.network :forwarded_port, guest: 3389, host: 3389, id: "rdp", auto_correct: true
config.vm.network :private_network, ip: "192.168.33.15", gateway: "192.168.33.1"
config.vm.communicator = "winrm"
config.winrm.username = "vagrant"
config.winrm.password = "vagrant"
config.vm.guest = :windows
config.windows.halt_timeout = 15
config.vm.provision "shell", inline: <<-SHELL
netsh.exe int ip show addresses
netsh.exe int ip set address "Ethernet 2" static 192.168.33.15 255.255.255.0 192.168.33.1
SHELL
["vmware_fusion", "vmware_workstation"].each do |provider|
config.vm.provider provider do |v, override|
v.gui = true
end
end
end
Can this small part be done by the vagrant-vmware-fusion as well? So for a user of Vagrant it just behaves like the virtualbox provider then.
Is the blocker here the lack of nic_mac_addresses capability in the vmware provider?
This should be relabeled guest/windows
from host/windows
.
It's disappointing that paid products like the vmware providers are less featured than their free open-source counterpart. And the problem has been reported...over a year ago...with no response.
The whole experience of using open-source vagrant with closed-source vmware providers is frustrating. You find a bug in vagrant and want to fix it? Ok but good luck getting your self-compiled vagrant to work with your vmware provider because of vagrant's "DRM". I feel like a less empowered second-rate citizen as a paying customer than people who are using only the free open-source parts of vagrant.
diff --git a/plugins/guests/windows/cap/configure_networks.rb b/plugins/guests/windows/cap/configure_networks.rb
index a4f4685..d628f99 100644
--- a/plugins/guests/windows/cap/configure_networks.rb
+++ b/plugins/guests/windows/cap/configure_networks.rb
@@ -16,33 +16,27 @@ module VagrantPlugins
@@logger.debug("Networks: #{networks.inspect}")
guest_network = GuestNetwork.new(machine.communicate)
- if machine.provider_name.to_s.start_with?("vmware")
- machine.ui.warn("Configuring secondary network adapters through VMware ")
- machine.ui.warn("on Windows is not yet supported. You will need to manually")
- machine.ui.warn("configure the network adapter.")
- else
- vm_interface_map = create_vm_interface_map(machine, guest_network)
- networks.each do |network|
- interface = vm_interface_map[network[:interface]+1]
- if interface.nil?
- @@logger.warn("Could not find interface for network #{network.inspect}")
- next
- end
+ vm_interface_map = create_vm_interface_map(machine, guest_network)
+ networks.each do |network|
+ interface = vm_interface_map[network[:interface]+1]
+ if interface.nil?
+ @@logger.warn("Could not find interface for network #{network.inspect}")
+ next
+ end
- network_type = network[:type].to_sym
- if network_type == :static
- guest_network.configure_static_interface(
- interface[:index],
- interface[:net_connection_id],
- network[:ip],
- network[:netmask])
- elsif network_type == :dhcp
- guest_network.configure_dhcp_interface(
- interface[:index],
- interface[:net_connection_id])
- else
- raise "#{network_type} network type is not supported, try static or dhcp"
- end
+ network_type = network[:type].to_sym
+ if network_type == :static
+ guest_network.configure_static_interface(
+ interface[:index],
+ interface[:net_connection_id],
+ network[:ip],
+ network[:netmask])
+ elsif network_type == :dhcp
+ guest_network.configure_dhcp_interface(
+ interface[:index],
+ interface[:net_connection_id])
+ else
+ raise "#{network_type} network type is not supported, try static or dhcp"
end
end
diff --git a/plugins/guests/windows/cap/nic_mac_addresses.rb b/plugins/guests/windows/cap/nic_mac_addresses.rb
new file mode 100644
index 0000000..d866ba2
--- /dev/null
+++ b/plugins/guests/windows/cap/nic_mac_addresses.rb
@@ -0,0 +1,41 @@
+require "log4r"
+
+module VagrantPlugins
+ module GuestWindows
+ module Cap
+ class NicMacAddresses
+ @@logger = Log4r::Logger.new("vagrant::guest::windows::cap::nic_mac_addresses")
+
+ def self.read_variable(machine, variable)
+ @@logger.debug("driver methods: #{machine.provider.driver.methods}")
+ result = machine.provider.driver.send(:vmrun, "readVariable", machine.id, "runtimeConfig", variable, retryable: true)
+ @@logger.debug("vmrun returned: #{result.exit_code} #{result.stdout} #{result.stderr}")
+ result.stdout.strip
+ end
+
+ def self.clean_mac(mac_address)
+ mac_address.gsub(':', '').upcase
+ end
+
+ def self.nic_mac_addresses(machine)
+ macs = []
+ i = 0
+ while true do
+ type = read_variable(machine, "ethernet#{i}.addressType")
+ case type
+ when "static"
+ macs.push(clean_mac(read_variable(machine, "ethernet#{i}.address")))
+ when "generated"
+ macs.push(clean_mac(read_variable(machine, "ethernet#{i}.generatedAddress")))
+ else
+ break
+ end
+ i += 1
+ end
+
+ Hash[macs.map.with_index{ |mac, index| [index+1, mac] }]
+ end
+ end
+ end
+ end
+end
diff --git a/plugins/guests/windows/plugin.rb b/plugins/guests/windows/plugin.rb
index d22dc27..d3d1d35 100644
--- a/plugins/guests/windows/plugin.rb
+++ b/plugins/guests/windows/plugin.rb
@@ -74,6 +74,11 @@ module VagrantPlugins
Cap::RSync
end
+ provider_capability(:vmware_fusion, :nic_mac_addresses) do
+ require_relative "cap/nic_mac_addresses"
+ Cap::NicMacAddresses
+ end
+
protected
def self.init!
Well after a few hours of tinkering, I was able to add the :nic_mac_addresses
capability to the vmware_fusion provider by hackily patching stuff up. This diff can be applied to /opt/vagrant/embedded/gems/gems/vagrant-1.8.1/
. But now it seems that configuring network adapters messes up the WinRM connection, but vagrant doesn't detect anything is out of order, so it just hangs waiting for the script output.
@bsuh Wow, great approach. Might be some inspiration for the Hashicorp team :pray: I have another issue that holds me from updating to 1.8.1 (again) but then I'll have a look at it.
diff --git a/plugins/communicators/winrm/communicator.rb b/plugins/communicators/winrm/communicator.rb
index e22a4f9..c39fb6b 100644
--- a/plugins/communicators/winrm/communicator.rb
+++ b/plugins/communicators/winrm/communicator.rb
@@ -102,7 +102,7 @@ module VagrantPlugins
@logger.info("Checking whether WinRM is ready...")
result = Timeout.timeout(@machine.config.winrm.timeout) do
- shell(true).powershell("hostname")
+ shell().powershell("hostname")
end
@logger.info("WinRM is ready!")
Fixed hanging while configuring network adapters inside the VM. At first, vagrant tries to connect to WinRM on the IP address of the first ethernet interface, but later tries to connect to WinRM on the IP address of the second ethernet interface to set the static ip address. Setting the static ip address of the interface that is holding the WinRM connection destroys the WinRM connection causing it to hang. Instead of always requesting the WinRM address to connect to using :winrm_info
, I made it reuse previous WinRM shell.
+1 for getting this enhancement into Vagrant. I've attempted to add
config.vm.provider "vmware_workstation" do |vmware|
vmware.vmx["ethernet1.connectionType"] = "bridged"
vmware.vmx["ethernet1.present"] = "TRUE"
vmware.vmx["ethernet1.virtualDev"] = "e1000e"
end
and receive the same message. RDPing into the machine shows that it has not received an extra, DHCP'd address as expected. Manually configuring bridged mode after a vagrant up
seems like a hassle in the face of the ease of performing this action with VirtualBox.
To patch the IP address of a second network card I wrote a small PowerShell script
cfg.vm.network :private_network, ip: "192.168.33.2", gateway: "192.168.33.1"
["vmware_fusion", "vmware_workstation"].each do |provider|
cfg.vm.provision "shell", path: "scripts/fix-second-network.ps1", privileged: false, args: "192.168.33.2"
end
and the script looks like this. It searches for the network interface with the given subnet and sets the fixed IP address. This script might be a basis for a PR to get this into Vagrants core.
param ([String] $ip)
$subnet = $ip -replace "\.\d+$", ""
$name = (Get-NetIPAddress -AddressFamily IPv4 `
| Where-Object -FilterScript { ($_.IPAddress).StartsWith($subnet) } `
).InterfaceAlias
if ($name) {
Write-Host "Set IP address to $ip of interface $name"
& netsh.exe int ip set address "$name" static $ip 255.255.255.0 "$subnet.1"
}
@StefanScherer I am trying to do the same thing as the remote vmware ESXI
provider with a Windows Guest. Couldn't find the right Autounattend.xml
syntax to set a static ip so now trying with netsh
.
Any of the examples here for using a provisioning script to set the interface configuration didn't work for me - it causes the provisioning step to hang. This is what I ended up doing as the last step. Note that even calling Start-ScheduledTask would cause the hang because the network config would be set while WinRM was connected. This step must be last for the same reason. If you need the IP to set for provisioning to continue, I suspect you could set the schedule task to start in 5 seconds, sleep for 10, and then continue. Hope it helps!
config.vm.provision "shell", privileged: false, name: "Schedule setting secondary interface", inline: <<-SHELL.gsub(/^ +/, '')
UnRegister-ScheduledTask SetIPConfig -EA SilentlyContinue
$A = New-ScheduledTaskAction -Execute "netsh.exe" -Argument "int ip set address Ethernet1 static 192.168.198.10 255.255.255.0"
$T = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(1)
$D = New-ScheduledTask -Action $A -Trigger $T
Register-ScheduledTask SetIPConfig -InputObject $D
SHELL
When a secondary NIC is configured for VMWare Vagrant issues the following error:
However, I can still configure a secondary NIC by doing:
Why doesn't Vagrant configure this by default when these same values are present in the
vmx
file?Base Box VMX File