Move hard drive action.

This commit is contained in:
Mitchell Hashimoto 2010-02-14 22:27:06 -08:00
parent ddfbe13b1d
commit 1753d97d45
3 changed files with 143 additions and 0 deletions

View File

@ -0,0 +1,43 @@
module Vagrant
module Actions
class MoveHardDrive < Base
def execute!
unless @vm.powered_off?
error_and_exit(<<-error)
The virtual machine must be powered off to move its disk.
error
return
end
destroy_drive_after { clone_and_attach }
end
# TODO: Better way to detect main bootup drive?
def hard_drive
@vm.storage_controllers.first.devices.first
end
def clone_and_attach
logger.info "Cloning current VM Disk to new location (#{new_image_path})..."
hard_drive.image = hard_drive.image.clone(new_image_path, Vagrant.config.vm.disk_image_format, true)
logger.info "Attaching new disk to VM ..."
@vm.vm.save
end
def destroy_drive_after
old_image = hard_drive.image
yield
logger.info "Destroying old VM Disk (#{old_image.filename})..."
old_image.destroy(true)
end
# Returns the path to the new location for the hard drive
def new_image_path
File.join(Vagrant.config.vm.hd_location, hard_drive.image.filename)
end
end
end
end

View File

@ -35,6 +35,7 @@ class Test::Unit::TestCase
config.vm.base = "foo"
config.vm.base_mac = "42"
config.vm.project_directory = "/hobo"
config.vm.disk_image_format = 'VMDK'
config.vm.forward_port("ssh", 22, 2222)
config.chef.cookbooks_path = "cookbooks"
@ -44,6 +45,12 @@ class Test::Unit::TestCase
}
end
if block_given?
Vagrant::Config.run do |config|
yield config
end
end
Vagrant::Config.execute!
end

View File

@ -0,0 +1,93 @@
require File.join(File.dirname(__FILE__), '..', '..', 'test_helper')
class MoveHardDriveActionTest < Test::Unit::TestCase
setup do
@mock_vm, @vm, @action = mock_action(Vagrant::Actions::MoveHardDrive)
@hd_location = "/foo"
mock_config do |config|
File.expects(:directory?).with(@hd_location).returns(true)
config.vm.hd_location = @hd_location
end
end
context "execution" do
should "error and exit if the vm is not powered off" do
@mock_vm.expects(:powered_off?).returns(false)
@action.expects(:error_and_exit).once
@action.execute!
end
should "move the hard drive if vm is powered off" do
@mock_vm.expects(:powered_off?).returns(true)
@action.expects(:error_and_exit).never
@action.expects(:destroy_drive_after).once
@action.execute!
end
end
context "new image path" do
setup do
@hd = mock("hd")
@image = mock("image")
@filename = "foo"
@hd.stubs(:image).returns(@image)
@image.stubs(:filename).returns(@filename)
@action.stubs(:hard_drive).returns(@hd)
end
should "be the configured hd location and the existing hard drive filename" do
joined = File.join(Vagrant.config.vm.hd_location, @filename)
assert_equal joined, @action.new_image_path
end
end
context "cloning and attaching new image" do
setup do
@hd = mock("hd")
@image = mock("image")
@hd.stubs(:image).returns(@image)
@action.stubs(:hard_drive).returns(@hd)
@new_image_path = "foo"
@action.stubs(:new_image_path).returns(@new_image_path)
end
should "clone to the new path" do
new_image = mock("new_image")
@image.expects(:clone).with(@new_image_path, Vagrant.config.vm.disk_image_format, true).returns(new_image).once
@hd.expects(:image=).with(new_image).once
@vm.expects(:save).once
@action.clone_and_attach
end
end
context "destroying the old image" do
setup do
@hd = mock("hd")
@action.stubs(:hard_drive).returns(@hd)
end
should "yield the block, and destroy the old image after" do
image = mock("image")
image.stubs(:filename).returns("foo")
destroy_seq = sequence("destroy_seq")
@hd.expects(:image).returns(image).in_sequence(destroy_seq)
@hd.expects(:foo).once.in_sequence(destroy_seq)
image.expects(:destroy).with(true).once.in_sequence(destroy_seq)
@action.destroy_drive_after { @hd.foo }
end
# Ensures that the image is not destroyed in an "ensure" block
should "not destroy the image if an exception is raised" do
image = mock("image")
image.expects(:destroy).never
@hd.expects(:image).returns(image)
assert_raises(Exception) do
@action.destroy_drive_after do
raise Exception.new("FOO")
end
end
end
end
end