diff --git a/lib/vagrant/systems/base.rb b/lib/vagrant/systems/base.rb index d2073c3db..85cb66421 100644 --- a/lib/vagrant/systems/base.rb +++ b/lib/vagrant/systems/base.rb @@ -27,6 +27,15 @@ module Vagrant @vm = vm end + # This method is automatically called when the system is available (when + # Vagrant can successfully SSH into the machine) to give the system a chance + # to determine the distro and return a distro-specific system. + # + # **Warning:** If a return value which subclasses from {Base} is + # returned, Vagrant will use it as the new system instance for the + # class. + def distro_dispatch; end + # Halt the machine. This method should gracefully shut down the # operating system. This method will cause `vagrant halt` and associated # commands to _block_, meaning that if the machine doesn't halt diff --git a/lib/vagrant/systems/linux.rb b/lib/vagrant/systems/linux.rb index 0da13e155..bf090a52d 100644 --- a/lib/vagrant/systems/linux.rb +++ b/lib/vagrant/systems/linux.rb @@ -1,32 +1,9 @@ +require 'vagrant/systems/linux/error' +require 'vagrant/systems/linux/config' + module Vagrant module Systems - # A general Vagrant system implementation for "linux." In general, - # any linux-based OS will work fine with this system, although its - # not tested exhaustively. BSD or other based systems may work as - # well, but that hasn't been tested at all. - # - # At any rate, this system implementation should server as an - # example of how to implement any custom systems necessary. class Linux < Base - # A custom config class which will be made accessible via `config.linux` - # This is not necessary for all system implementers, of course. However, - # generally, Vagrant tries to make almost every aspect of its execution - # configurable, and this assists that goal. - class LinuxConfig < Vagrant::Config::Base - configures :linux - - attr_accessor :halt_timeout - attr_accessor :halt_check_interval - - def initialize - @halt_timeout = 30 - @halt_check_interval = 1 - end - end - - #------------------------------------------------------------------- - # Overridden methods - #------------------------------------------------------------------- def halt vm.env.ui.info I18n.t("vagrant.systems.linux.attempting_halt") vm.ssh.execute do |ssh| @@ -111,11 +88,5 @@ module Vagrant end end end - - class Linux < Base - class LinuxError < Errors::VagrantError - error_namespace("vagrant.systems.linux") - end - end end end diff --git a/lib/vagrant/systems/linux/config.rb b/lib/vagrant/systems/linux/config.rb new file mode 100644 index 000000000..a98a7f4ad --- /dev/null +++ b/lib/vagrant/systems/linux/config.rb @@ -0,0 +1,21 @@ +module Vagrant + module Systems + class Linux < Vagrant::Systems::Base + # A custom config class which will be made accessible via `config.linux` + # This is not necessary for all system implementers, of course. However, + # generally, Vagrant tries to make almost every aspect of its execution + # configurable, and this assists that goal. + class LinuxConfig < Vagrant::Config::Base + configures :linux + + attr_accessor :halt_timeout + attr_accessor :halt_check_interval + + def initialize + @halt_timeout = 30 + @halt_check_interval = 1 + end + end + end + end +end diff --git a/lib/vagrant/systems/linux/error.rb b/lib/vagrant/systems/linux/error.rb new file mode 100644 index 000000000..b1f033b25 --- /dev/null +++ b/lib/vagrant/systems/linux/error.rb @@ -0,0 +1,9 @@ +module Vagrant + module Systems + class Linux < Vagrant::Systems::Base + class LinuxError < Errors::VagrantError + error_namespace("vagrant.systems.linux") + end + end + end +end diff --git a/lib/vagrant/vm.rb b/lib/vagrant/vm.rb index 99d857ad1..6d01c9718 100644 --- a/lib/vagrant/vm.rb +++ b/lib/vagrant/vm.rb @@ -3,7 +3,6 @@ module Vagrant include Vagrant::Util attr_reader :env - attr_reader :system attr_reader :name attr_reader :vm @@ -41,6 +40,8 @@ module Vagrant # Load the associated system. load_system! end + + @loaded_system_distro = false end # Loads the system associated with the VM. The system class is @@ -48,8 +49,8 @@ module Vagrant # can be found by reading the documentation on {Vagrant::Systems::Base}. # # **This method should never be called manually.** - def load_system! - system = env.config.vm.system + def load_system!(system=nil) + system ||= env.config.vm.system if system.is_a?(Class) @system = system.new(self) @@ -65,6 +66,19 @@ module Vagrant end end + # Returns the system for this VM, loading the distro of the system if + # we can. + def system + if !@loaded_system_distro && created? && vm.running? + # Load the system distro for the first time + result = @system.distro_dispatch + load_system!(result) + @loaded_system_distro = true + end + + @system + end + # Access the {Vagrant::SSH} object associated with this VM. # On the initial call, this will initialize the object. On # subsequent calls it will reuse the existing object. diff --git a/test/vagrant/vm_test.rb b/test/vagrant/vm_test.rb index 9325a7325..a6b622ddd 100644 --- a/test/vagrant/vm_test.rb +++ b/test/vagrant/vm_test.rb @@ -25,6 +25,7 @@ class VMTest < Test::Unit::TestCase setup do @vm_name = "foo" @mock_vm = mock("vm") + @mock_vm.stubs(:running?).returns(false) @vm = Vagrant::VM.new(:env => @env, :vm => @mock_vm, :name => @vm_name) @mock_vm.stubs(:uuid).returns("foo") end @@ -96,11 +97,14 @@ class VMTest < Test::Unit::TestCase } end - context "with a class" do - class FakeSystemClass - def initialize(vm); end - end + should "load the given system if specified" do + fake_class = Class.new(Vagrant::Systems::Base) + assert_nothing_raised { @vm.load_system!(fake_class) } + assert @vm.system.is_a?(fake_class) + end + + context "with a class" do should "initialize class if given" do @vm.env.config.vm.system = Vagrant::Systems::Linux @@ -109,7 +113,7 @@ class VMTest < Test::Unit::TestCase end should "raise error if class has invalid parent" do - @vm.env.config.vm.system = FakeSystemClass + @vm.env.config.vm.system = Class.new assert_raises(Vagrant::Errors::VMSystemError) { @vm.load_system! } @@ -140,6 +144,30 @@ class VMTest < Test::Unit::TestCase } end end + + context "loading the distro" do + setup do + @vm.vm.stubs(:running?).returns(true) + end + + should "not replace the distro if it is nil" do + @vm.env.config.vm.system = Class.new(Vagrant::Systems::Base) + + @vm.load_system! + assert @vm.system.is_a?(@vm.env.config.vm.system) + end + + should "replace the distro if it is not nil" do + @vm.env.config.vm.system = Class.new(Vagrant::Systems::Base) do + def distro_dispatch + :linux + end + end + + @vm.load_system! + assert @vm.system.is_a?(Vagrant::Systems::Linux) + end + end end context "uuid" do