diff --git a/lib/vagrant/actions/vm/boot.rb b/lib/vagrant/actions/vm/boot.rb new file mode 100644 index 000000000..494b9b81e --- /dev/null +++ b/lib/vagrant/actions/vm/boot.rb @@ -0,0 +1,50 @@ +module Vagrant + module Actions + module VM + class Boot < Base + def execute! + @runner.invoke_around_callback(:boot) do + # Startup the VM + boot + + # Wait for it to complete booting, or error if we could + # never detect it booted up successfully + if !wait_for_boot + error_and_exit(<<-error) +Failed to connect to VM! Failed to boot? +error + end + end + end + + def collect_shared_folders + # The root shared folder for the project + ["vagrant-root", Env.root_path, Vagrant.config.vm.project_directory] + end + + def boot + logger.info "Booting VM..." + @runner.vm.start(:headless, true) + end + + def wait_for_boot(sleeptime=5) + logger.info "Waiting for VM to boot..." + + Vagrant.config[:ssh][:max_tries].to_i.times do |i| + logger.info "Trying to connect (attempt ##{i+1} of #{Vagrant.config[:ssh][:max_tries]})..." + + if Vagrant::SSH.up? + logger.info "VM booted and ready for use!" + return true + end + + sleep sleeptime + end + + logger.info "Failed to connect to VM! Failed to boot?" + false + end + end + end + end +end diff --git a/lib/vagrant/actions/vm/start.rb b/lib/vagrant/actions/vm/start.rb index 1e4038b82..5e7fc1a66 100644 --- a/lib/vagrant/actions/vm/start.rb +++ b/lib/vagrant/actions/vm/start.rb @@ -2,48 +2,15 @@ module Vagrant module Actions module VM class Start < Base - def execute! - @runner.invoke_around_callback(:boot) do - # Startup the VM - boot + def prepare + # Start is a "meta-action" so it really just queues up a bunch + # of other actions in its place: + steps = [ForwardPorts, SharedFolders, Boot] - # Wait for it to complete booting, or error if we could - # never detect it booted up successfully - if !wait_for_boot - error_and_exit(<<-error) -Failed to connect to VM! Failed to boot? -error - end + steps.each do |action_klass| + @runner.add_action(action_klass) end end - - def collect_shared_folders - # The root shared folder for the project - ["vagrant-root", Env.root_path, Vagrant.config.vm.project_directory] - end - - def boot - logger.info "Booting VM..." - @runner.vm.start(:headless, true) - end - - def wait_for_boot(sleeptime=5) - logger.info "Waiting for VM to boot..." - - Vagrant.config[:ssh][:max_tries].to_i.times do |i| - logger.info "Trying to connect (attempt ##{i+1} of #{Vagrant.config[:ssh][:max_tries]})..." - - if Vagrant::SSH.up? - logger.info "VM booted and ready for use!" - return true - end - - sleep sleeptime - end - - logger.info "Failed to connect to VM! Failed to boot?" - false - end end end end diff --git a/lib/vagrant/actions/vm/up.rb b/lib/vagrant/actions/vm/up.rb index 7f67a0f5f..190fc64f1 100644 --- a/lib/vagrant/actions/vm/up.rb +++ b/lib/vagrant/actions/vm/up.rb @@ -16,7 +16,7 @@ msg # Up is a "meta-action" so it really just queues up a bunch # of other actions in its place: - steps = [Import, ForwardPorts, SharedFolders, Start] + steps = [Import, ForwardPorts, SharedFolders, Boot] steps << Provision if Vagrant.config.chef.enabled steps.insert(0, MoveHardDrive) if Vagrant.config.vm.hd_location diff --git a/lib/vagrant/vm.rb b/lib/vagrant/vm.rb index 660bdc44c..df4bab42d 100644 --- a/lib/vagrant/vm.rb +++ b/lib/vagrant/vm.rb @@ -28,12 +28,7 @@ module Vagrant def start return if @vm.running? - actions = [Actions::VM::ForwardPorts, Actions::VM::SharedFolders, Actions::VM::Start] - actions.each do |action| - add_action(action) - end - - execute! + execute!(Actions::VM::Start) end def destroy diff --git a/test/vagrant/actions/vm/boot_test.rb b/test/vagrant/actions/vm/boot_test.rb new file mode 100644 index 000000000..729426854 --- /dev/null +++ b/test/vagrant/actions/vm/boot_test.rb @@ -0,0 +1,55 @@ +require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper') + +class BootActionTest < Test::Unit::TestCase + setup do + @mock_vm, @vm, @action = mock_action(Vagrant::Actions::VM::Boot) + @mock_vm.stubs(:invoke_callback) + mock_config + end + + context "execution" do + should "invoke the 'boot' around callback" do + boot_seq = sequence("boot_seq") + @mock_vm.expects(:invoke_around_callback).with(:boot).once.in_sequence(boot_seq).yields + @action.expects(:boot).in_sequence(boot_seq) + @action.expects(:wait_for_boot).returns(true).in_sequence(boot_seq) + @action.execute! + end + + should "error and exit if the bootup failed" do + fail_boot_seq = sequence("fail_boot_seq") + @action.expects(:boot).once.in_sequence(fail_boot_seq) + @action.expects(:wait_for_boot).returns(false).in_sequence(fail_boot_seq) + @action.expects(:error_and_exit).once.in_sequence(fail_boot_seq) + @action.execute! + end + end + + context "booting" do + should "start the VM in headless mode" do + @vm.expects(:start).with(:headless, true).once + @action.boot + end + end + + context "waiting for boot" do + should "repeatedly ping the SSH port and return false with no response" do + seq = sequence('pings') + Vagrant::SSH.expects(:up?).times(Vagrant.config[:ssh][:max_tries].to_i - 1).returns(false).in_sequence(seq) + Vagrant::SSH.expects(:up?).once.returns(true).in_sequence(seq) + assert @action.wait_for_boot(0) + end + + should "ping the max number of times then just return" do + Vagrant::SSH.expects(:up?).times(Vagrant.config[:ssh][:max_tries].to_i).returns(false) + assert !@action.wait_for_boot(0) + end + end + + context "callbacks" do + should "setup the root directory shared folder" do + expected = ["vagrant-root", Vagrant::Env.root_path, Vagrant.config.vm.project_directory] + assert_equal expected, @action.collect_shared_folders + end + end +end diff --git a/test/vagrant/actions/vm/start_test.rb b/test/vagrant/actions/vm/start_test.rb index 885a18635..d054a15f2 100644 --- a/test/vagrant/actions/vm/start_test.rb +++ b/test/vagrant/actions/vm/start_test.rb @@ -3,53 +3,26 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper') class StartActionTest < Test::Unit::TestCase setup do @mock_vm, @vm, @action = mock_action(Vagrant::Actions::VM::Start) - @mock_vm.stubs(:invoke_callback) mock_config end - context "execution" do - should "invoke the 'boot' around callback" do - boot_seq = sequence("boot_seq") - @mock_vm.expects(:invoke_around_callback).with(:boot).once.in_sequence(boot_seq).yields - @action.expects(:boot).in_sequence(boot_seq) - @action.expects(:wait_for_boot).returns(true).in_sequence(boot_seq) - @action.execute! + context "sub-actions" do + setup do + File.stubs(:file?).returns(true) + File.stubs(:exist?).returns(true) + @default_order = [Vagrant::Actions::VM::ForwardPorts, Vagrant::Actions::VM::SharedFolders, Vagrant::Actions::VM::Boot] end - should "error and exit if the bootup failed" do - fail_boot_seq = sequence("fail_boot_seq") - @action.expects(:boot).once.in_sequence(fail_boot_seq) - @action.expects(:wait_for_boot).returns(false).in_sequence(fail_boot_seq) - @action.expects(:error_and_exit).once.in_sequence(fail_boot_seq) - @action.execute! - end - end - - context "booting" do - should "start the VM in headless mode" do - @vm.expects(:start).with(:headless, true).once - @action.boot - end - end - - context "waiting for boot" do - should "repeatedly ping the SSH port and return false with no response" do - seq = sequence('pings') - Vagrant::SSH.expects(:up?).times(Vagrant.config[:ssh][:max_tries].to_i - 1).returns(false).in_sequence(seq) - Vagrant::SSH.expects(:up?).once.returns(true).in_sequence(seq) - assert @action.wait_for_boot(0) + def setup_action_expectations + default_seq = sequence("default_seq") + @default_order.each do |action| + @mock_vm.expects(:add_action).with(action).once.in_sequence(default_seq) + end end - should "ping the max number of times then just return" do - Vagrant::SSH.expects(:up?).times(Vagrant.config[:ssh][:max_tries].to_i).returns(false) - assert !@action.wait_for_boot(0) - end - end - - context "callbacks" do - should "setup the root directory shared folder" do - expected = ["vagrant-root", Vagrant::Env.root_path, Vagrant.config.vm.project_directory] - assert_equal expected, @action.collect_shared_folders + should "do the proper actions by default" do + setup_action_expectations + @action.prepare end end end diff --git a/test/vagrant/actions/vm/up_test.rb b/test/vagrant/actions/vm/up_test.rb index 1ce641a4e..520c70194 100644 --- a/test/vagrant/actions/vm/up_test.rb +++ b/test/vagrant/actions/vm/up_test.rb @@ -10,7 +10,7 @@ class UpActionTest < Test::Unit::TestCase setup do File.stubs(:file?).returns(true) File.stubs(:exist?).returns(true) - @default_order = [Vagrant::Actions::VM::Import, Vagrant::Actions::VM::ForwardPorts, Vagrant::Actions::VM::SharedFolders, Vagrant::Actions::VM::Start] + @default_order = [Vagrant::Actions::VM::Import, Vagrant::Actions::VM::ForwardPorts, Vagrant::Actions::VM::SharedFolders, Vagrant::Actions::VM::Boot] end def setup_action_expectations diff --git a/test/vagrant/vm_test.rb b/test/vagrant/vm_test.rb index a420d70ec..94c48de0b 100644 --- a/test/vagrant/vm_test.rb +++ b/test/vagrant/vm_test.rb @@ -80,15 +80,8 @@ class VMTest < Test::Unit::TestCase @vm.start end - should "add and execute the proper actions" do - actions = [Vagrant::Actions::VM::ForwardPorts, Vagrant::Actions::VM::SharedFolders, Vagrant::Actions::VM::Start] - - action_seq = sequence("action_seq") - actions.each do |action| - @vm.expects(:add_action).with(action).in_sequence(action_seq) - end - - @vm.expects(:execute!).once.in_sequence(action_seq) + should "execute the start action" do + @vm.expects(:execute!).once.with(Vagrant::Actions::VM::Start) @vm.start end end