Fix issue with infinite looping on `vagrant resume`

This commit is contained in:
Mitchell Hashimoto 2010-03-08 18:45:59 -08:00
parent db24291b3d
commit 2f7de333ec
8 changed files with 129 additions and 96 deletions

View File

@ -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

View File

@ -2,47 +2,14 @@ module Vagrant
module Actions module Actions
module VM module VM
class Start < Base class Start < Base
def execute! def prepare
@runner.invoke_around_callback(:boot) do # Start is a "meta-action" so it really just queues up a bunch
# Startup the VM # of other actions in its place:
boot steps = [ForwardPorts, SharedFolders, Boot]
# Wait for it to complete booting, or error if we could steps.each do |action_klass|
# never detect it booted up successfully @runner.add_action(action_klass)
if !wait_for_boot end
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 end

View File

@ -16,7 +16,7 @@ msg
# Up is a "meta-action" so it really just queues up a bunch # Up is a "meta-action" so it really just queues up a bunch
# of other actions in its place: # of other actions in its place:
steps = [Import, ForwardPorts, SharedFolders, Start] steps = [Import, ForwardPorts, SharedFolders, Boot]
steps << Provision if Vagrant.config.chef.enabled steps << Provision if Vagrant.config.chef.enabled
steps.insert(0, MoveHardDrive) if Vagrant.config.vm.hd_location steps.insert(0, MoveHardDrive) if Vagrant.config.vm.hd_location

View File

@ -28,12 +28,7 @@ module Vagrant
def start def start
return if @vm.running? return if @vm.running?
actions = [Actions::VM::ForwardPorts, Actions::VM::SharedFolders, Actions::VM::Start] execute!(Actions::VM::Start)
actions.each do |action|
add_action(action)
end
execute!
end end
def destroy def destroy

View File

@ -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

View File

@ -3,53 +3,26 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
class StartActionTest < Test::Unit::TestCase class StartActionTest < Test::Unit::TestCase
setup do setup do
@mock_vm, @vm, @action = mock_action(Vagrant::Actions::VM::Start) @mock_vm, @vm, @action = mock_action(Vagrant::Actions::VM::Start)
@mock_vm.stubs(:invoke_callback)
mock_config mock_config
end end
context "execution" do context "sub-actions" do
should "invoke the 'boot' around callback" do setup do
boot_seq = sequence("boot_seq") File.stubs(:file?).returns(true)
@mock_vm.expects(:invoke_around_callback).with(:boot).once.in_sequence(boot_seq).yields File.stubs(:exist?).returns(true)
@action.expects(:boot).in_sequence(boot_seq) @default_order = [Vagrant::Actions::VM::ForwardPorts, Vagrant::Actions::VM::SharedFolders, Vagrant::Actions::VM::Boot]
@action.expects(:wait_for_boot).returns(true).in_sequence(boot_seq)
@action.execute!
end end
should "error and exit if the bootup failed" do def setup_action_expectations
fail_boot_seq = sequence("fail_boot_seq") default_seq = sequence("default_seq")
@action.expects(:boot).once.in_sequence(fail_boot_seq) @default_order.each do |action|
@action.expects(:wait_for_boot).returns(false).in_sequence(fail_boot_seq) @mock_vm.expects(:add_action).with(action).once.in_sequence(default_seq)
@action.expects(:error_and_exit).once.in_sequence(fail_boot_seq)
@action.execute!
end end
end end
context "booting" do should "do the proper actions by default" do
should "start the VM in headless mode" do setup_action_expectations
@vm.expects(:start).with(:headless, true).once @action.prepare
@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 end
end end

View File

@ -10,7 +10,7 @@ class UpActionTest < Test::Unit::TestCase
setup do setup do
File.stubs(:file?).returns(true) File.stubs(:file?).returns(true)
File.stubs(:exist?).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 end
def setup_action_expectations def setup_action_expectations

View File

@ -80,15 +80,8 @@ class VMTest < Test::Unit::TestCase
@vm.start @vm.start
end end
should "add and execute the proper actions" do should "execute the start action" do
actions = [Vagrant::Actions::VM::ForwardPorts, Vagrant::Actions::VM::SharedFolders, Vagrant::Actions::VM::Start] @vm.expects(:execute!).once.with(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)
@vm.start @vm.start
end end
end end