diff --git a/lib/vagrant/actions/start.rb b/lib/vagrant/actions/start.rb new file mode 100644 index 000000000..06b9865d5 --- /dev/null +++ b/lib/vagrant/actions/start.rb @@ -0,0 +1,45 @@ +module Vagrant + module Actions + class Start < Base + def execute! + @vm.invoke_callback(:before_boot) + + # 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 + + @vm.invoke_callback(:after_boot) + end + + def boot + logger.info "Booting VM..." + @vm.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 \ No newline at end of file diff --git a/test/vagrant/actions/start_test.rb b/test/vagrant/actions/start_test.rb new file mode 100644 index 000000000..078501963 --- /dev/null +++ b/test/vagrant/actions/start_test.rb @@ -0,0 +1,50 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'test_helper') + +class StartActionTest < Test::Unit::TestCase + setup do + @mock_vm, @vm, @action = mock_action(Vagrant::Actions::Start) + @mock_vm.stubs(:invoke_callback) + mock_config + end + + context "execution" do + should "invoke before callback, boot, and invoke the after callback" do + boot_seq = sequence("boot_seq") + @mock_vm.expects(:invoke_callback).with(:before_boot).once.in_sequence(boot_seq) + @action.expects(:boot).in_sequence(boot_seq) + @action.expects(:wait_for_boot).returns(true).in_sequence(boot_seq) + @mock_vm.expects(:invoke_callback).with(:after_boot).once.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(:invoke_callback).with(:after_boot).never + @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 +end