From e7e1badbdc204d50fc18b0aaeb8420c9d63d79de Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Fri, 14 Oct 2022 10:44:49 -0700 Subject: [PATCH] Add support for VirtualBox 7.0 --- lib/vagrant/errors.rb | 4 + plugins/providers/virtualbox/driver/meta.rb | 1 + .../virtualbox/driver/version_7_0.rb | 67 +++++++++++ plugins/providers/virtualbox/plugin.rb | 1 + templates/locales/en.yml | 5 + .../virtualbox/driver/version_7_0_test.rb | 109 ++++++++++++++++++ 6 files changed, 187 insertions(+) create mode 100644 plugins/providers/virtualbox/driver/version_7_0.rb create mode 100644 test/unit/plugins/providers/virtualbox/driver/version_7_0_test.rb diff --git a/lib/vagrant/errors.rb b/lib/vagrant/errors.rb index 7f868f22e..42dd927ef 100644 --- a/lib/vagrant/errors.rb +++ b/lib/vagrant/errors.rb @@ -972,6 +972,10 @@ module Vagrant error_key(:virtualbox_broken_version_040214) end + class VirtualBoxConfigNotFound < VagrantError + error_key(:virtualbox_config_not_found) + end + class VirtualBoxDisksDefinedExceedLimit < VagrantError error_key(:virtualbox_disks_defined_exceed_limit) end diff --git a/plugins/providers/virtualbox/driver/meta.rb b/plugins/providers/virtualbox/driver/meta.rb index c3be8c873..04c130c44 100644 --- a/plugins/providers/virtualbox/driver/meta.rb +++ b/plugins/providers/virtualbox/driver/meta.rb @@ -65,6 +65,7 @@ module VagrantPlugins "5.2" => Version_5_2, "6.0" => Version_6_0, "6.1" => Version_6_1, + "7.0" => Version_7_0, } if @@version.start_with?("4.2.14") diff --git a/plugins/providers/virtualbox/driver/version_7_0.rb b/plugins/providers/virtualbox/driver/version_7_0.rb new file mode 100644 index 000000000..d94e66b93 --- /dev/null +++ b/plugins/providers/virtualbox/driver/version_7_0.rb @@ -0,0 +1,67 @@ +require "rexml" +require File.expand_path("../version_6_1", __FILE__) + +module VagrantPlugins + module ProviderVirtualBox + module Driver + # Driver for VirtualBox 7.0.x + class Version_7_0 < Version_6_1 + def initialize(uuid) + super + + @logger = Log4r::Logger.new("vagrant::provider::virtualbox_7_0") + end + + # The initial VirtualBox 7.0 release has an issue with displaying port + # forward information. When a single port forward is defined, the forwarding + # information can be found in the `showvminfo` output. Once more than a + # single port forward is defined, no forwarding information is provided + # in the `showvminfo` output. To work around this we grab the VM configuration + # file from the `showvminfo` output and extract the port forward information + # from there instead. + def read_forwarded_ports(uuid=nil, active_only=false) + @version ||= Meta.new.version + + # Only use this override for the 7.0.0 release. If it is still broken + # on the 7.0.1 release we can modify the version check. + return super if @version != "7.0.0" + + uuid ||= @uuid + + @logger.debug("read_forward_ports: uuid=#{uuid} active_only=#{active_only}") + + results = [] + + info = execute("showvminfo", uuid, "--machinereadable", retryable: true) + result = info.match(/CfgFile="(?.+?)"/) + if result.nil? + raise Vagrant::Errors::VirtualBoxConfigNotFound, + uuid: uuid + end + + File.open(result[:path], "r") do |f| + doc = REXML::Document.new(f) + networks = REXML::XPath.each(doc.root, "//Adapter") + networks.each do |net| + REXML::XPath.each(doc.root, net.xpath + "/NAT/Forwarding") do |fwd| + # Result Array values: + # [NIC Slot, Name, Host Port, Guest Port, Host IP] + result = [ + net.attribute("slot").value.to_i + 1, + fwd.attribute("name")&.value.to_s, + fwd.attribute("hostport")&.value.to_i, + fwd.attribute("guestport")&.value.to_i, + fwd.attribute("hostip")&.value.to_s + ] + @logger.debug(" - #{result.inspect}") + results << result + end + end + end + + results + end + end + end + end +end diff --git a/plugins/providers/virtualbox/plugin.rb b/plugins/providers/virtualbox/plugin.rb index 8d63e6d9f..3b447c5c2 100644 --- a/plugins/providers/virtualbox/plugin.rb +++ b/plugins/providers/virtualbox/plugin.rb @@ -100,6 +100,7 @@ module VagrantPlugins autoload :Version_5_2, File.expand_path("../driver/version_5_2", __FILE__) autoload :Version_6_0, File.expand_path("../driver/version_6_0", __FILE__) autoload :Version_6_1, File.expand_path("../driver/version_6_1", __FILE__) + autoload :Version_7_0, File.expand_path("../driver/version_7_0", __FILE__) end module Model diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 2ea04d938..a0d3962fd 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -1743,6 +1743,11 @@ en: 4.2.14 contains a critical bug which prevents it from working with Vagrant. VirtualBox 4.2.16+ fixes this problem. Please upgrade VirtualBox. + virtualbox_config_not_found: |- + Vagrant was unable to locate the configuration file for the requested + VirtualBox VM. Verify the requested VM exists and try again. + + UUID provided: %{uuid} virtualbox_disks_controller_not_found: |- Vagrant expected to find a storage controller called '%{name}', but there is no controller with this name attached to the current VM. 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 new file mode 100644 index 000000000..58c9e6dac --- /dev/null +++ b/test/unit/plugins/providers/virtualbox/driver/version_7_0_test.rb @@ -0,0 +1,109 @@ +require "stringio" +require_relative "../base" + +describe VagrantPlugins::ProviderVirtualBox::Driver::Version_7_0 do + include_context "virtualbox" + + let(:vbox_version) { "7.0.0" } + + subject { VagrantPlugins::ProviderVirtualBox::Driver::Version_7_0.new(uuid) } + + it_behaves_like "a version 5.x virtualbox driver" + it_behaves_like "a version 6.x virtualbox driver" + + describe "#read_forwarded_ports" do + let(:uuid) { "MACHINE-UUID" } + let(:cfg_path) { "MACHINE_CONFIG_PATH" } + let(:vm_info) { +%(name="vagrant-test_default_1665781960041_56631" +Encryption: disabled +groups="/" +ostype="Ubuntu (64-bit)" +UUID="#{uuid}" +CfgFile="#{cfg_path}" +SnapFldr="/VirtualBox VMs/vagrant-test_default_1665781960041_56631/Snapshots" +LogFldr="/VirtualBox VMs/vagrant-test_default_1665781960041_56631/Logs" +memory=1024) + } + let(:config_file) { + StringIO.new( +%( + + + + + + + + + + + + + + + + + + + + + +) + ) + } + + before do + allow_any_instance_of(VagrantPlugins::ProviderVirtualBox::Driver::Meta).to receive(:version).and_return(vbox_version) + end + + describe "VirtualBox version 7.0.0" do + let(:vbox_version) { "7.0.0" } + + before do + allow(subject).to receive(:execute).with("showvminfo", uuid, any_args).and_return(vm_info) + allow(File).to receive(:open).with(cfg_path, "r").and_yield(config_file) + end + + it "should return two port forward values" do + expect(subject.read_forwarded_ports.size).to eq(2) + end + + it "should have port forwards on slot one" do + subject.read_forwarded_ports.each do |fwd| + expect(fwd.first).to eq(1) + end + end + + it "should include host ip for ssh forward" do + fwd = subject.read_forwarded_ports.detect { |f| f[1] == "ssh" } + expect(fwd).not_to be_nil + expect(fwd.last).to eq("127.0.0.1") + end + + describe "when config file cannot be determine" do + let(:vm_info) { %(name="vagrant-test_default_1665781960041_56631") } + + it "should raise a custom error" do + expect(File).not_to receive(:open).with(cfg_path, "r") + + expect { subject.read_forwarded_ports }.to raise_error(Vagrant::Errors::VirtualBoxConfigNotFound) + end + end + end + + describe "VirtualBox version greater than 7.0.0" do + let(:vbox_version) { "7.0.1" } + + before do + allow(subject).to receive(:execute).with("showvminfo", uuid, any_args).and_return(vm_info) + end + + it "should not read configuration file" do + expect(File).not_to receive(:open).with(cfg_path, "r") + subject.read_forwarded_ports + end + end + + end +end