From 9e4047533d80a1dc8e71cbb53ad0e9e6f839c355 Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Thu, 10 Nov 2022 16:56:52 -0800 Subject: [PATCH] Customize #read_network_interfaces for hostonlynetworks Adds an override for the #read_network_interfaces when hostonlynetworks are in use to properly identify the hostonly network information from the guest. This also adjusts the IP provided for the network to be the first in the subnet. --- .../virtualbox/driver/version_7_0.rb | 27 ++++- .../virtualbox/driver/version_7_0_test.rb | 98 +++++++++++++++++++ 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/plugins/providers/virtualbox/driver/version_7_0.rb b/plugins/providers/virtualbox/driver/version_7_0.rb index efa820b62..a12c4a791 100644 --- a/plugins/providers/virtualbox/driver/version_7_0.rb +++ b/plugins/providers/virtualbox/driver/version_7_0.rb @@ -157,11 +157,11 @@ module VagrantPlugins addr = IPAddr.new(net[:lowerip]) net[:netmask] = net[:networkmask] if addr.ipv4? - net[:ip] = addr.mask(net[:netmask]).to_s + net[:ip] = addr.mask(net[:netmask]).succ.to_s net[:ipv6] = "" else net[:ip] = "" - net[:ipv6] = addr.mask(net[:netmwask]).to_s + net[:ipv6] = addr.mask(net[:netmwask]).succ.to_s net[:ipv6_prefix] = net[:netmask] end @@ -171,6 +171,29 @@ module VagrantPlugins end end + def read_network_interfaces + return super if !use_host_only_nets? + + {}.tap do |nics| + execute("showvminfo", @uuid, "--machinereadable", retryable: true).each_line do |line| + if m = line.match(/nic(?\d+)="(?.+?)"$/) + nics[m[:adapter].to_i] ||= {} + if m[:type] == "hostonlynetwork" + nics[m[:adapter].to_i][:type] = :hostonly + else + nics[m[:adapter].to_i][:type] = m[:type].to_sym + end + elsif m = line.match(/^bridgeadapter(?\d+)="(?.+?)"$/) + nics[m[:adapter].to_i] ||= {} + nics[m[:adapter].to_i][:bridge] = m[:network] + elsif m = line.match(/^hostonly-network(?\d+)="(?.+?)"$/) + nics[m[:adapter].to_i] ||= {} + nics[m[:adapter].to_i][:hostonly] = m[:network] + end + end + end + end + # Generate list of host only networks def read_host_only_networks networks = [] diff --git a/test/unit/plugins/providers/virtualbox/driver/version_7_0_test.rb b/test/unit/plugins/providers/virtualbox/driver/version_7_0_test.rb index 2f2d3695e..d1a91fe37 100644 --- a/test/unit/plugins/providers/virtualbox/driver/version_7_0_test.rb +++ b/test/unit/plugins/providers/virtualbox/driver/version_7_0_test.rb @@ -563,6 +563,12 @@ memory=1024) expect(result.first[:netmask]).to eq(result.first[:networkmask]) expect(result.first[:status]).to eq("Up") end + + it "should assign the address as the first in the subnet" do + result = subject.read_host_only_interfaces + ip = IPAddr.new(result.first[:lowerip]).mask(result.first[:networkmask]) + expect(result.first[:ip]).to eq(ip.succ.to_s) + end end end @@ -586,6 +592,71 @@ memory=1024) expect(result.last[:networkmask]).to eq("255.255.255.0") end end + + describe "#read_network_interfaces" do + before do + allow(subject) + .to receive(:execute). + with("showvminfo", any_args). + and_return(VBOX_GUEST_HOSTONLYVNETS_INFO) + end + + context "when hostonlynets is disabled" do + before do + allow(subject).to receive(:use_host_only_nets?).and_return(false) + end + + it "should return two interfaces" do + valid_interfaces = subject.read_network_interfaces.find_all { |k, v| + v[:type] != :none + } + expect(valid_interfaces.size).to eq(2) + end + + it "should include a nat type" do + expect(subject.read_network_interfaces.detect { |_, v| v[:type] == :nat }).to be + end + + it "should include a hostonlynetwork type with no information" do + expect(subject.read_network_interfaces[2]).to eq({type: :hostonlynetwork}) + end + end + + context "when hostonlynets is enabled" do + before do + allow(subject).to receive(:use_host_only_nets?).and_return(true) + end + + it "should return two interfaces" do + valid_interfaces = subject.read_network_interfaces.find_all { |k, v| + v[:type] != :none + } + expect(valid_interfaces.size).to eq(2) + end + + it "should include a nat type" do + expect(subject.read_network_interfaces.detect { |_, v| v[:type] == :nat }).to be + end + + it "should include a hostonly type" do + expect(subject.read_network_interfaces.detect { |_, v| v[:type] == :hostonly }).to be + end + + it "should not include a hostonlynetwork type" do + expect(subject.read_network_interfaces.detect { |_, v| + v[:type] == :hostonlynetwork + }).to_not be + end + + it "should include the hostonly network name" do + hostonly = subject.read_network_interfaces.values.detect { |v| + v[:type] == :hostonly + } + expect(hostonly).to be + expect(hostonly[:hostonly]).to eq("vagrantnet-vbox1") + end + end + end end VBOX_VMCONFIG_FILE=%( @@ -695,3 +766,30 @@ NetworkMask: 255.255.255.0 LowerIP: 192.168.22.0 UpperIP: 192.168.22.0 VBoxNetworkName: hostonly-vagrantnet-vbox2) + +VBOX_GUEST_HOSTONLYVNETS_INFO=%( +natnet1="nat" +macaddress1="080027BB1475" +cableconnected1="on" +nic1="nat" +nictype1="82540EM" +nicspeed1="0" +mtu="0" +sockSnd="64" +sockRcv="64" +tcpWndSnd="64" +tcpWndRcv="64" +Forwarding(0)="ssh,tcp,127.0.0.1,2222,,22" +hostonly-network2="vagrantnet-vbox1" +macaddress2="080027FBC15B" +cableconnected2="on" +nic2="hostonlynetwork" +nictype2="82540EM" +nicspeed2="0" +nic3="none" +nic4="none" +nic5="none" +nic6="none" +nic7="none" +nic8="none" +)