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:
parent
c9d341ae2b
commit
d0f728b353
|
@ -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
|
|
@ -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
|
|
@ -7,6 +7,8 @@ require 'pathname'
|
||||||
require 'logger'
|
require 'logger'
|
||||||
require 'virtualbox'
|
require 'virtualbox'
|
||||||
require 'net/ssh'
|
require 'net/ssh'
|
||||||
|
require 'ping'
|
||||||
|
require 'hobo/error'
|
||||||
require 'hobo/config'
|
require 'hobo/config'
|
||||||
require 'hobo/env'
|
require 'hobo/env'
|
||||||
require 'hobo/ssh'
|
require 'hobo/ssh'
|
||||||
|
|
|
@ -7,6 +7,8 @@ module Hobo
|
||||||
# Initialize class variables used
|
# Initialize class variables used
|
||||||
@@persisted_vm = nil
|
@@persisted_vm = nil
|
||||||
@@root_path = nil
|
@@root_path = nil
|
||||||
|
|
||||||
|
extend Hobo::Error
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def persisted_vm; @@persisted_vm; end
|
def persisted_vm; @@persisted_vm; end
|
||||||
|
@ -79,17 +81,6 @@ error
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def error_and_exit(error)
|
|
||||||
puts <<-error
|
|
||||||
=====================================================================
|
|
||||||
Hobo experienced an error!
|
|
||||||
|
|
||||||
#{error.chomp}
|
|
||||||
=====================================================================
|
|
||||||
error
|
|
||||||
exit
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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
|
|
@ -2,7 +2,7 @@ module Hobo
|
||||||
class SSH
|
class SSH
|
||||||
SCRIPT = File.join(File.dirname(__FILE__), '..', '..', 'script', 'hobo-ssh-expect.sh')
|
SCRIPT = File.join(File.dirname(__FILE__), '..', '..', 'script', 'hobo-ssh-expect.sh')
|
||||||
|
|
||||||
class <<self
|
class << self
|
||||||
def connect(opts={})
|
def connect(opts={})
|
||||||
options = {}
|
options = {}
|
||||||
[:port, :host, :pass, :uname].each do |param|
|
[:port, :host, :pass, :uname].each do |param|
|
||||||
|
@ -17,6 +17,10 @@ module Hobo
|
||||||
yield ssh
|
yield ssh
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def up?
|
||||||
|
Ping.pingecho "localhost", 1, Hobo.config[:ssh][:port]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,9 @@ module Hobo
|
||||||
class VM
|
class VM
|
||||||
attr_reader :vm
|
attr_reader :vm
|
||||||
|
|
||||||
class <<self
|
extend Hobo::Error
|
||||||
|
|
||||||
|
class << self
|
||||||
# Bring up the virtual machine. Imports the base image and
|
# Bring up the virtual machine. Imports the base image and
|
||||||
# provisions it.
|
# provisions it.
|
||||||
def up
|
def up
|
||||||
|
@ -21,6 +23,27 @@ module Hobo
|
||||||
SSH.connect
|
SSH.connect
|
||||||
end
|
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
|
# Finds a virtual machine by a given UUID and either returns
|
||||||
# a Hobo::VM object or returns nil.
|
# a Hobo::VM object or returns nil.
|
||||||
def find(uuid)
|
def find(uuid)
|
||||||
|
@ -94,23 +117,23 @@ module Hobo
|
||||||
|
|
||||||
# Now we have to wait for the boot to be successful
|
# Now we have to wait for the boot to be successful
|
||||||
HOBO_LOGGER.info "Waiting for VM to boot..."
|
HOBO_LOGGER.info "Waiting for VM to boot..."
|
||||||
counter = 1
|
|
||||||
begin
|
Hobo.config[:ssh][:max_tries].to_i.times do |i|
|
||||||
sleep 5 unless ENV['HOBO_ENV'] == 'test'
|
sleep 5 unless ENV['HOBO_ENV'] == 'test'
|
||||||
HOBO_LOGGER.info "Trying to connect (attempt ##{counter} of #{Hobo.config[:ssh][:max_tries]})..."
|
HOBO_LOGGER.info "Trying to connect (attempt ##{i+1} of #{Hobo.config[:ssh][:max_tries]})..."
|
||||||
SSH.execute { |ssh| }
|
|
||||||
rescue Errno::ECONNREFUSED
|
if Hobo::SSH.up?
|
||||||
if counter >= Hobo.config[:ssh][:max_tries].to_i
|
HOBO_LOGGER.info "VM booted and ready for use!"
|
||||||
HOBO_LOGGER.info "Failed to connect to VM! Failed to boot?"
|
return true
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
counter += 1
|
|
||||||
retry
|
|
||||||
end
|
end
|
||||||
|
|
||||||
HOBO_LOGGER.info "VM booted and ready for use!"
|
HOBO_LOGGER.info "Failed to connect to VM! Failed to boot?"
|
||||||
true
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def saved?; @vm.saved? end
|
||||||
|
|
||||||
|
def save_state(errs); @vm.save_state(errs) end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -112,15 +112,15 @@ class VMTest < Test::Unit::TestCase
|
||||||
@vm.start
|
@vm.start
|
||||||
end
|
end
|
||||||
|
|
||||||
should "repeatedly SSH while waiting for the VM to start" do
|
should "repeatedly ping the SSH port and return false with no response" do
|
||||||
ssh_seq = sequence("ssh_seq")
|
seq = sequence('pings')
|
||||||
Net::SSH.expects(:start).once.raises(Errno::ECONNREFUSED).in_sequence(ssh_seq)
|
Ping.expects(:pingecho).times(Hobo.config[:ssh][:max_tries].to_i - 1).returns(false).in_sequence(seq)
|
||||||
Net::SSH.expects(:start).once.in_sequence(ssh_seq)
|
Ping.expects(:pingecho).once.returns(true).in_sequence(seq)
|
||||||
@vm.start
|
assert @vm.start
|
||||||
end
|
end
|
||||||
|
|
||||||
should "try the max number of times then just return" do
|
should "ping the max number of times then just return" do
|
||||||
Net::SSH.expects(:start).times(Hobo.config[:ssh][:max_tries].to_i).raises(Errno::ECONNREFUSED)
|
Ping.expects(:pingecho).times(Hobo.config[:ssh][:max_tries].to_i).returns(false)
|
||||||
assert !@vm.start
|
assert !@vm.start
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -182,5 +182,48 @@ class VMTest < Test::Unit::TestCase
|
||||||
@vm.setup_shared_folder
|
@vm.setup_shared_folder
|
||||||
end
|
end
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue