`vagrant halt` now attempts to gracefully shut down the machine (via System#halt)

This commit is contained in:
Mitchell Hashimoto 2010-04-25 16:27:03 -07:00
parent 0736f8582d
commit d5866a1b54
7 changed files with 79 additions and 7 deletions

View File

@ -6,8 +6,12 @@ module Vagrant
raise ActionException.new(:vm_not_running) unless @runner.vm.running?
@runner.invoke_around_callback(:halt) do
logger.info "Forcing shutdown of VM..."
@runner.vm.stop
@runner.system.halt
if @runner.vm.state(true) != :powered_off
logger.info "Forcing shutdown of VM..."
@runner.vm.stop
end
end
end
end

View File

@ -27,6 +27,15 @@ module Vagrant
@vm = vm
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
# in a reasonable amount of time, this method should just return.
#
# If when this method returns, the machine's state isn't "powered_off,"
# Vagrant will proceed to forcefully shut the machine down.
def halt; end
# Mounts a shared folder. This method is called by the shared
# folder action with an open SSH session (passed in as `ssh`).
# This method should create, mount, and properly set permissions

View File

@ -11,6 +11,24 @@ module Vagrant
#-------------------------------------------------------------------
# Overridden methods
#-------------------------------------------------------------------
def halt
logger.info "Attempting graceful shutdown of linux..."
vm.env.ssh.execute do |ssh|
ssh.exec!("sudo halt")
end
# Wait until the VM's state is actually powered off. If this doesn't
# occur within a reasonable amount of time (15 seconds by default),
# then simply return and allow Vagrant to kill the machine.
count = 0
while vm.vm.state(true) != :powered_off
count += 1
return if count >= 15
sleep 1
end
end
def mount_shared_folder(ssh, name, guestpath)
ssh.exec!("sudo mkdir -p #{guestpath}")
mount_folder(ssh, name, guestpath)

View File

@ -87,9 +87,16 @@ class Test::Unit::TestCase
mock_vm.stubs(:actions).returns([action])
mock_vm.stubs(:env).returns(mock_environment)
vm.stubs(:env).returns(mock_vm.env)
[mock_vm, vm, action]
end
# Returns a linux system
def linux_system(vm)
Vagrant::Systems::Linux.new(vm)
end
def stub_default_action_dependecies(mock)
mock.stubs(:precedes).returns([])
mock.stubs(:follows).returns([])

View File

@ -3,21 +3,35 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
class HaltActionTest < Test::Unit::TestCase
setup do
@runner, @vm, @action = mock_action(Vagrant::Actions::VM::Halt)
@runner.stubs(:system).returns(linux_system(@vm))
end
context "executing" do
setup do
@vm.stubs(:running?).returns(true)
@runner.system.stubs(:halt)
@vm.stubs(:stop)
@vm.stubs(:state).returns(:powered_off)
end
should "invoke the 'halt' around callback" do
halt_seq = sequence("halt_seq")
@runner.expects(:invoke_around_callback).with(:halt).once.in_sequence(halt_seq).yields
@vm.expects(:stop).in_sequence(halt_seq)
@runner.expects(:invoke_around_callback).with(:halt).once
@action.execute!
end
should "force the VM to stop" do
should "halt with the system and NOT force VM to stop if powered off" do
@vm.expects(:state).with(true).returns(:powered_off)
@runner.system.expects(:halt).once
@vm.expects(:stop).never
@action.execute!
end
should "halt with the system and force VM to stop if NOT powered off" do
@vm.expects(:state).with(true).returns(:running)
@runner.system.expects(:halt).once
@vm.expects(:stop).once
@action.execute!
end

View File

@ -3,7 +3,7 @@ require File.join(File.dirname(__FILE__), '..', '..', '..', 'test_helper')
class SharedFoldersActionTest < Test::Unit::TestCase
setup do
@runner, @vm, @action = mock_action(Vagrant::Actions::VM::SharedFolders)
@runner.stubs(:system).returns(Vagrant::Systems::Linux.new(@vm))
@runner.stubs(:system).returns(linux_system(@vm))
end
def stub_shared_folders

View File

@ -9,6 +9,26 @@ class LinuxSystemTest < Test::Unit::TestCase
@instance = @klass.new(@vm)
end
context "halting" do
setup do
@ssh_session = mock("ssh_session")
@ssh = mock("ssh")
@ssh.stubs(:execute).yields(@ssh_session)
@vm.env.stubs(:ssh).returns(@ssh)
@real_vm = mock("real_vm")
@real_vm.stubs(:state).returns(:powered_off)
@vm.stubs(:vm).returns(@real_vm)
end
should "execute halt via SSH" do
@ssh_session.expects(:exec!).with("sudo halt").once
@instance.halt
end
# TODO: Sleep/timeout testing
end
context "mounting shared folders" do
setup do
@ssh = mock("ssh")