suspend and resume, test for both and failures, small refactor of the Hobo::VM#start and the use of Ping.pingecho in SSH.up?

This commit is contained in:
John Bender 2010-02-02 00:48:38 -08:00
parent c9d341ae2b
commit d0f728b353
8 changed files with 163 additions and 34 deletions

26
bin/hobo-resume Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env ruby
begin
require File.expand_path(File.join(File.dirname(__FILE__), "../vendor/gems/ruby/1.8/environment"))
rescue LoadError
end
require 'git-style-binary/command'
# Get hobo
hobodir = File.join(File.dirname(__FILE__), '..', 'lib')
$:.unshift(hobodir) unless $:.include?(hobodir)
require 'hobo'
GitStyleBinary.command do
short_desc "resumes the hobo environment"
banner <<-EOS
Usage: #{command.full_name} #{all_options_string}
Resumes the hobo environment.
EOS
run do |command|
Hobo::VM.resume
end
end

26
bin/hobo-suspend Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env ruby
begin
require File.expand_path(File.join(File.dirname(__FILE__), "../vendor/gems/ruby/1.8/environment"))
rescue LoadError
end
require 'git-style-binary/command'
# Get hobo
hobodir = File.join(File.dirname(__FILE__), '..', 'lib')
$:.unshift(hobodir) unless $:.include?(hobodir)
require 'hobo'
GitStyleBinary.command do
short_desc "suspends the hobo environment"
banner <<-EOS
Usage: #{command.full_name} #{all_options_string}
Suspends the hobo environment.
EOS
run do |command|
Hobo::VM.suspend
end
end

View File

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

View File

@ -8,6 +8,8 @@ module Hobo
@@persisted_vm = nil
@@root_path = nil
extend Hobo::Error
class << self
def persisted_vm; @@persisted_vm; end
def root_path; @@root_path; end
@ -79,17 +81,6 @@ error
return
end
end
def error_and_exit(error)
puts <<-error
=====================================================================
Hobo experienced an error!
#{error.chomp}
=====================================================================
error
exit
end
end
end
end

14
lib/hobo/error.rb Normal file
View File

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

View File

@ -2,7 +2,7 @@ module Hobo
class SSH
SCRIPT = File.join(File.dirname(__FILE__), '..', '..', 'script', 'hobo-ssh-expect.sh')
class <<self
class << self
def connect(opts={})
options = {}
[:port, :host, :pass, :uname].each do |param|
@ -17,6 +17,10 @@ module Hobo
yield ssh
end
end
def up?
Ping.pingecho "localhost", 1, Hobo.config[:ssh][:port]
end
end
end
end

View File

@ -2,7 +2,9 @@ module Hobo
class VM
attr_reader :vm
class <<self
extend Hobo::Error
class << self
# Bring up the virtual machine. Imports the base image and
# provisions it.
def up
@ -21,6 +23,27 @@ module Hobo
SSH.connect
end
# Save the state of the current hobo environment to disk
def suspend
Env.require_persisted_vm
error_and_exit(<<-error) if Env.persisted_vm.saved?
The hobo virtual environment you are trying to reume is already in a
suspended state.
error
Env.persisted_vm.save_state(true)
end
# Resume the current hobo environment from disk
def resume
Env.require_persisted_vm
error_and_exit(<<-error) unless Env.persisted_vm.saved?
The hobo virtual environment you are trying to resume is not in a
suspended state.
error
Env.persisted_vm.start
end
# Finds a virtual machine by a given UUID and either returns
# a Hobo::VM object or returns nil.
def find(uuid)
@ -94,23 +117,23 @@ module Hobo
# Now we have to wait for the boot to be successful
HOBO_LOGGER.info "Waiting for VM to boot..."
counter = 1
begin
sleep 5 unless ENV['HOBO_ENV'] == 'test'
HOBO_LOGGER.info "Trying to connect (attempt ##{counter} of #{Hobo.config[:ssh][:max_tries]})..."
SSH.execute { |ssh| }
rescue Errno::ECONNREFUSED
if counter >= Hobo.config[:ssh][:max_tries].to_i
HOBO_LOGGER.info "Failed to connect to VM! Failed to boot?"
return false
end
counter += 1
retry
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]})..."
if Hobo::SSH.up?
HOBO_LOGGER.info "VM booted and ready for use!"
return true
end
end
HOBO_LOGGER.info "VM booted and ready for use!"
true
HOBO_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
end
end

View File

@ -112,15 +112,15 @@ class VMTest < Test::Unit::TestCase
@vm.start
end
should "repeatedly SSH while waiting for the VM to start" do
ssh_seq = sequence("ssh_seq")
Net::SSH.expects(:start).once.raises(Errno::ECONNREFUSED).in_sequence(ssh_seq)
Net::SSH.expects(:start).once.in_sequence(ssh_seq)
@vm.start
should "repeatedly ping the SSH port and return false with no response" do
seq = sequence('pings')
Ping.expects(:pingecho).times(Hobo.config[:ssh][:max_tries].to_i - 1).returns(false).in_sequence(seq)
Ping.expects(:pingecho).once.returns(true).in_sequence(seq)
assert @vm.start
end
should "try the max number of times then just return" do
Net::SSH.expects(:start).times(Hobo.config[:ssh][:max_tries].to_i).raises(Errno::ECONNREFUSED)
should "ping the max number of times then just return" do
Ping.expects(:pingecho).times(Hobo.config[:ssh][:max_tries].to_i).returns(false)
assert !@vm.start
end
end
@ -182,5 +182,48 @@ class VMTest < Test::Unit::TestCase
@vm.setup_shared_folder
end
end
context "suspending a vm" do
should "put the vm in a suspended state" do
saved_state_expectations(false)
Hobo::VM.suspend
end
should "results in an error and exit if the vm is already in a saved state" do
saved_state_expectations(true)
Hobo::VM.expects(:error_and_exit)
Hobo::VM.suspend
end
def saved_state_expectations(saved)
@persisted_vm.expects(:saved?).returns(saved)
# In this case the exit, is ignored so the expectation of save_state on the persisted
# vm must be set
@persisted_vm.expects(:save_state).with(true)
end
end
context "resuming a vm" do
should "start a vm in a suspended state" do
start_state_expectaions(true)
Hobo::VM.resume
end
should "results in an error and exit if the vm is not in a saved state" do
start_state_expectaions(false)
# In this case the exit, is ignored so the expectation of start on the persisted
# vm must be set
# TODO research the matter of mocking exit
Hobo::VM.expects(:error_and_exit)
Hobo::VM.resume
end
def start_state_expectaions(saved)
@persisted_vm.expects(:saved?).returns(saved)
Hobo::Env.persisted_vm.expects(:start).once.returns(true)
end
end
end
end