From 19f82e72aa7b36b4d29122324341f0811ef8bbed Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 9 Feb 2010 00:21:27 -0800 Subject: [PATCH] VM shared folders can now be added easily. --- lib/hobo/vm.rb | 60 ++++++++++++++++++++--------- test/hobo/vm_test.rb | 90 ++++++++++++++++++++++++++++---------------- 2 files changed, 100 insertions(+), 50 deletions(-) diff --git a/lib/hobo/vm.rb b/lib/hobo/vm.rb index 119a96632..2ec9cf952 100644 --- a/lib/hobo/vm.rb +++ b/lib/hobo/vm.rb @@ -25,7 +25,6 @@ module Hobo SSH.connect end - # Save the state of the current hobo environment to disk def suspend Env.require_persisted_vm @@ -61,14 +60,16 @@ error end def create + share_folder("hobo-root", Env.root_path, Hobo.config.vm.project_directory) + import move_hd if Hobo.config[:vm][:hd_location] persist setup_mac_address forward_ports - setup_shared_folder + setup_shared_folders start - mount_shared_folder + mount_shared_folders end def destroy @@ -93,7 +94,7 @@ error # TODO image extension default? new_image = hd.image.clone(new_image_file , HD_EXT_DEFAULT, true) hd.image = new_image - + logger.info "Attaching new disk to VM ..." @vm.save @@ -132,20 +133,28 @@ error @vm.save(true) end - def setup_shared_folder - logger.info "Creating shared folders..." - folder = VirtualBox::SharedFolder.new - folder.name = "hobo-root-path" - folder.hostpath = Env.root_path - @vm.shared_folders << folder + def setup_shared_folders + logger.info "Creating shared folders metadata..." + + shared_folders.each do |name, hostpath, guestpath| + folder = VirtualBox::SharedFolder.new + folder.name = name + folder.hostpath = hostpath + @vm.shared_folders << folder + end + @vm.save(true) end - def mount_shared_folder - HOBO_LOGGER.info "Mounting shared folders..." + def mount_shared_folders + logger.info "Mounting shared folders..." + Hobo::SSH.execute do |ssh| - ssh.exec!("sudo mkdir -p #{Hobo.config.vm.project_directory}") - ssh.exec!("sudo mount -t vboxsf hobo-root-path #{Hobo.config.vm.project_directory}") + shared_folders.each do |name, hostpath, guestpath| + logger.info "-- #{name}: #{guestpath}" + ssh.exec!("sudo mkdir -p #{guestpath}") + ssh.exec!("sudo mount -t vboxsf #{name} #{guestpath}") + end end end @@ -155,7 +164,7 @@ error # Now we have to wait for the boot to be successful logger.info "Waiting for VM to boot..." - + Hobo.config[:ssh][:max_tries].to_i.times do |i| sleep 5 unless ENV['HOBO_ENV'] == 'test' logger.info "Trying to connect (attempt ##{i+1} of #{Hobo.config[:ssh][:max_tries]})..." @@ -170,11 +179,26 @@ error false end - def saved?; @vm.saved? end + def shared_folders(clear=false) + @shared_folders = nil if clear + @shared_folders ||= [] + end - def save_state(errs); @vm.save_state(errs) end + def share_folder(name, hostpath, guestpath) + shared_folders << [name, hostpath, guestpath] + end + + def saved? + @vm.saved? + end + + def save_state(errs) + @vm.save_state(errs) + end # TODO need a better way to which controller is the hd - def hd; @vm.storage_controllers.first.devices.first end + def hd + @vm.storage_controllers.first.devices.first + end end end diff --git a/test/hobo/vm_test.rb b/test/hobo/vm_test.rb index ff11e1a5e..4be2105a9 100644 --- a/test/hobo/vm_test.rb +++ b/test/hobo/vm_test.rb @@ -78,9 +78,9 @@ class VMTest < Test::Unit::TestCase @vm.expects(:persist).in_sequence(create_seq) @vm.expects(:setup_mac_address).in_sequence(create_seq) @vm.expects(:forward_ports).in_sequence(create_seq) - @vm.expects(:setup_shared_folder).in_sequence(create_seq) + @vm.expects(:setup_shared_folders).in_sequence(create_seq) @vm.expects(:start).in_sequence(create_seq) - @vm.expects(:mount_shared_folder).in_sequence(create_seq) + @vm.expects(:mount_shared_folders).in_sequence(create_seq) @vm.create end end @@ -170,31 +170,6 @@ class VMTest < Test::Unit::TestCase end end - context "setting up the shared folder" do - should "create a shared folder with the root folder for the VM" do - shared_folder = mock("shared_folder") - shared_folder.stubs(:name=) - shared_folder.expects(:hostpath=).with(Hobo::Env.root_path).once - shared_folder_collection = mock("collection") - shared_folder_collection.expects(:<<).with(shared_folder) - VirtualBox::SharedFolder.expects(:new).returns(shared_folder) - @mock_vm.expects(:shared_folders).returns(shared_folder_collection) - @mock_vm.expects(:save).with(true).once - @vm.setup_shared_folder - end - end - - context "mounting the shared folders" do - should "create the directory then mount the shared folder" do - mount_seq = sequence("mount_seq") - ssh = mock("ssh") - ssh.expects(:exec!).with("sudo mkdir -p #{Hobo.config.vm.project_directory}").in_sequence(mount_seq) - ssh.expects(:exec!).with("sudo mount -t vboxsf hobo-root-path #{Hobo.config.vm.project_directory}").in_sequence(mount_seq) - Hobo::SSH.expects(:execute).yields(ssh) - @vm.mount_shared_folder - end - end - context "suspending and resuming a vm" do should "put the vm in a suspended state" do saved_state_expectation(false) @@ -235,9 +210,60 @@ class VMTest < Test::Unit::TestCase Hobo::Env.persisted_vm.expects(:start).once.returns(true) end end - - context "creating a new vm with a specified disk storage location" do + context "shared folders" do + setup do + @mock_vm = mock("mock_vm") + @vm = Hobo::VM.new(@mock_vm) + end + + should "not have any shared folders initially" do + assert @vm.shared_folders.empty? + end + + should "be able to add shared folders" do + @vm.share_folder("foo", "from", "to") + assert_equal 1, @vm.shared_folders.length + end + + should "be able to clear shared folders" do + @vm.share_folder("foo", "from", "to") + assert !@vm.shared_folders.empty? + @vm.shared_folders(true) + assert @vm.shared_folders.empty? + end + + should "add all shared folders to the VM with 'setup_shared_folders'" do + @vm.share_folder("foo", "from", "to") + @vm.share_folder("bar", "bfrom", "bto") + + share_seq = sequence("share_seq") + shared_folders = mock("shared_folders") + shared_folders.expects(:<<).in_sequence(share_seq).with() { |sf| sf.name == "foo" && sf.hostpath == "from" } + shared_folders.expects(:<<).in_sequence(share_seq).with() { |sf| sf.name == "bar" && sf.hostpath == "bfrom" } + @mock_vm.stubs(:shared_folders).returns(shared_folders) + @mock_vm.expects(:save).with(true).once + + @vm.setup_shared_folders + end + + should "mount all shared folders to the VM with `mount_shared_folders`" do + @vm.share_folder("foo", "from", "to") + @vm.share_folder("bar", "bfrom", "bto") + + mount_seq = sequence("mount_seq") + ssh = mock("ssh") + @vm.shared_folders.each do |name, hostpath, guestpath| + ssh.expects(:exec!).with("sudo mkdir -p #{guestpath}").in_sequence(mount_seq) + ssh.expects(:exec!).with("sudo mount -t vboxsf #{name} #{guestpath}").in_sequence(mount_seq) + end + Hobo::SSH.expects(:execute).yields(ssh) + + @vm.mount_shared_folders + end + end + + context "creating a new vm with a specified disk storage location" do should "error and exit of the vm is not powered off" do # Exit does not prevent method from proceeding in test, so we must set expectations vm = move_hd_expectations @@ -245,7 +271,7 @@ class VMTest < Test::Unit::TestCase vm.expects(:error_and_exit) vm.move_hd end - + should "create assign a new disk image, and delete the old one" do vm = move_hd_expectations @mock_vm.expects(:powered_off?).returns(true) @@ -261,11 +287,11 @@ class VMTest < Test::Unit::TestCase hd.expects(:image).twice.returns(image) hd.expects(:image=).with(image) - + image.expects(:destroy) @mock_vm.expects(:save) - + vm = Hobo::VM.new(@mock_vm) vm.expects(:hd).times(3).returns(hd) vm