move_hd during hobo up

This commit is contained in:
John Bender 2010-02-07 19:56:56 -08:00
parent 7fd4ee0160
commit 3a3fbb44c7
7 changed files with 98 additions and 25 deletions

View File

@ -8,7 +8,7 @@ require 'logger'
require 'virtualbox'
require 'net/ssh'
require 'ping'
require 'hobo/error'
require 'hobo/util'
require 'hobo/config'
require 'hobo/env'
require 'hobo/ssh'

View File

@ -7,7 +7,7 @@ module Hobo
@config = nil
@config_runners = []
class <<self
class << self
def config
@config ||= Config::Top.new
end
@ -48,6 +48,7 @@ module Hobo
attr_accessor :base_mac
attr_accessor :project_directory
attr_reader :forwarded_ports
attr_accessor :hd_location
def initialize
@forwarded_ports = {}
@ -60,6 +61,11 @@ module Hobo
:protocol => protocol
}
end
def hd_location=(val)
raise Exception.new "disk_storage must be set to a directory" unless File.directory?(val)
@hd_location=val
end
end
class Top < Base

View File

@ -8,7 +8,7 @@ module Hobo
@@persisted_vm = nil
@@root_path = nil
extend Hobo::Error
extend Hobo::Util
class << self
def persisted_vm; @@persisted_vm; end

View File

@ -1,14 +1,19 @@
module Hobo
module Error
def error_and_exit(error)
puts <<-error
module Util
def error_and_exit(error)
puts <<-error
=====================================================================
Hobo experienced an error!
#{error.chomp}
=====================================================================
error
exit
end
exit
end
def logger
HOBO_LOGGER
end
end
end
end

View File

@ -1,8 +1,10 @@
module Hobo
class VM
HD_EXT_DEFAULT = 'VMDK'
attr_reader :vm
extend Hobo::Error
extend Hobo::Util
include Hobo::Util
class << self
# Bring up the virtual machine. Imports the base image and
@ -28,9 +30,10 @@ module Hobo
def suspend
Env.require_persisted_vm
error_and_exit(<<-error) if Env.persisted_vm.saved?
The hobo virtual environment you are trying to resume is already in a
The hobo virtual environment you are trying to suspend is already in a
suspended state.
error
logger.info "Saving VM state..."
Env.persisted_vm.save_state(true)
end
@ -59,6 +62,7 @@ error
def create
import
move_hd if Hobo.config[:vm][:hd_location]
persist
setup_mac_address
forward_ports
@ -69,26 +73,46 @@ error
def destroy
if @vm.running?
HOBO_LOGGER.info "VM is running. Forcing immediate shutdown..."
logger.info "VM is running. Forcing immediate shutdown..."
@vm.stop(true)
end
HOBO_LOGGER.info "Destroying VM and associated drives..."
logger.info "Destroying VM and associated drives..."
@vm.destroy(:destroy_image => true)
end
def move_hd
error_and_exit(<<-error) unless @vm.powered_off?
The virtual machine must be powered off to move its disk.
error
old_image = hd.image.dup
new_image_file = Hobo.config[:vm][:hd_location] + old_image.filename
logger.info "Cloning current VM Disk to new location (#{ new_image_file })..."
# 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
logger.info "Destroying old VM Disk (#{ old_image.filename })..."
old_image.destroy(true)
end
def import
HOBO_LOGGER.info "Importing base VM (#{Hobo.config[:vm][:base]})..."
logger.info "Importing base VM (#{Hobo.config[:vm][:base]})..."
@vm = VirtualBox::VM.import(File.expand_path(Hobo.config[:vm][:base]))
end
def persist
HOBO_LOGGER.info "Persisting the VM UUID (#{@vm.uuid})..."
logger.info "Persisting the VM UUID (#{@vm.uuid})..."
Env.persist_vm(@vm)
end
def setup_mac_address
HOBO_LOGGER.info "Matching MAC addresses..."
logger.info "Matching MAC addresses..."
@vm.nics.first.macaddress = Hobo.config[:vm][:base_mac]
@vm.save(true)
end
@ -109,7 +133,7 @@ error
end
def setup_shared_folder
HOBO_LOGGER.info "Creating shared folders..."
logger.info "Creating shared folders..."
folder = VirtualBox::SharedFolder.new
folder.name = "hobo-root-path"
folder.hostpath = Env.root_path
@ -126,28 +150,31 @@ error
end
def start
HOBO_LOGGER.info "Booting VM..."
logger.info "Booting VM..."
@vm.start(:headless, true)
# Now we have to wait for the boot to be successful
HOBO_LOGGER.info "Waiting for VM to boot..."
logger.info "Waiting for VM to boot..."
Hobo.config[:ssh][:max_tries].to_i.times do |i|
sleep 5 unless ENV['HOBO_ENV'] == 'test'
HOBO_LOGGER.info "Trying to connect (attempt ##{i+1} of #{Hobo.config[:ssh][:max_tries]})..."
logger.info "Trying to connect (attempt ##{i+1} of #{Hobo.config[:ssh][:max_tries]})..."
if Hobo::SSH.up?
HOBO_LOGGER.info "VM booted and ready for use!"
logger.info "VM booted and ready for use!"
return true
end
end
HOBO_LOGGER.info "Failed to connect to VM! Failed to boot?"
logger.info "Failed to connect to VM! Failed to boot?"
false
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
end
end

View File

@ -11,10 +11,9 @@ if { $port != "" } {
set port_option ""
}
spawn ssh $port_option $uname@$host
spawn ssh $port_option -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $uname@$host
expect "*password: " {
sleep 1
send "$password\r"
} timeout {
send_user "Error connecting"

View File

@ -235,5 +235,41 @@ 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
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
@mock_vm.expects(:powered_off?).returns(false)
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)
vm.move_hd
end
def move_hd_expectations
image, hd = mock('image'), mock('hd')
Hobo.config[:vm].expects(:hd_location).at_least_once.returns('/locations/')
image.expects(:clone).with(Hobo.config[:vm][:hd_location] + 'foo', Hobo::VM::HD_EXT_DEFAULT, true).returns(image)
image.expects(:filename).twice.returns('foo')
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
end
end
end
end