`vagrant resume` works with the new machine abstraction

This commit is contained in:
Mitchell Hashimoto 2012-08-13 20:03:35 -07:00
parent db11c16b79
commit bca8663742
5 changed files with 166 additions and 17 deletions

View File

@ -4,10 +4,8 @@ module VagrantPlugins
module CommandResume module CommandResume
class Command < Vagrant.plugin("1", :command) class Command < Vagrant.plugin("1", :command)
def execute def execute
options = {} opts = OptionParser.new do |o|
o.banner = "Usage: vagrant resume [vm-name]"
opts = OptionParser.new do |opts|
opts.banner = "Usage: vagrant resume [vm-name]"
end end
# Parse the options # Parse the options
@ -15,19 +13,13 @@ module VagrantPlugins
return if !argv return if !argv
@logger.debug("'resume' each target VM...") @logger.debug("'resume' each target VM...")
with_target_vms(argv) do |vm| with_target_vms(argv) do |machine|
if vm.created? machine.action(:resume)
@logger.info("Resume: #{vm.name}")
vm.resume
else
@logger.info("Not created: #{vm.name}. Not resuming.")
vm.ui.info I18n.t("vagrant.commands.common.vm_not_created")
end
end end
# Success, exit status 0 # Success, exit status 0
0 0
end end
end end
end end
end end

View File

@ -3,8 +3,10 @@ require "vagrant/action/builder"
module VagrantPlugins module VagrantPlugins
module ProviderVirtualBox module ProviderVirtualBox
module Action module Action
autoload :Boot, File.expand_path("../action/boot", __FILE__)
autoload :CheckAccessible, File.expand_path("../action/check_accessible", __FILE__) autoload :CheckAccessible, File.expand_path("../action/check_accessible", __FILE__)
autoload :CheckCreated, File.expand_path("../action/check_created", __FILE__) autoload :CheckCreated, File.expand_path("../action/check_created", __FILE__)
autoload :CheckPortCollisions, File.expand_path("../action/check_port_collisions", __FILE__)
autoload :CheckRunning, File.expand_path("../action/check_running", __FILE__) autoload :CheckRunning, File.expand_path("../action/check_running", __FILE__)
autoload :CheckVirtualbox, File.expand_path("../action/check_virtualbox", __FILE__) autoload :CheckVirtualbox, File.expand_path("../action/check_virtualbox", __FILE__)
autoload :Created, File.expand_path("../action/created", __FILE__) autoload :Created, File.expand_path("../action/created", __FILE__)
@ -13,6 +15,7 @@ module VagrantPlugins
autoload :Halt, File.expand_path("../action/halt", __FILE__) autoload :Halt, File.expand_path("../action/halt", __FILE__)
autoload :MessageNotCreated, File.expand_path("../action/message_not_created", __FILE__) autoload :MessageNotCreated, File.expand_path("../action/message_not_created", __FILE__)
autoload :MessageWillNotDestroy, File.expand_path("../action/message_will_not_destroy", __FILE__) autoload :MessageWillNotDestroy, File.expand_path("../action/message_will_not_destroy", __FILE__)
autoload :Resume, File.expand_path("../action/resume", __FILE__)
autoload :Suspend, File.expand_path("../action/suspend", __FILE__) autoload :Suspend, File.expand_path("../action/suspend", __FILE__)
# Include the built-in modules so that we can use them as top-level # Include the built-in modules so that we can use them as top-level
@ -59,6 +62,23 @@ module VagrantPlugins
end end
end end
# This is the action that is primarily responsible for resuming
# suspended machines.
def self.action_resume
Vagrant::Action::Builder.new.tap do |b|
b.use CheckVirtualbox
b.use Call, Created do |env, b2|
if env[:result]
b2.use CheckAccessible
b2.use CheckPortCollisions
b2.use Resume
else
b2.use MessageNotCreated
end
end
end
end
# This is the action that will exec into an SSH shell. # This is the action that will exec into an SSH shell.
def self.action_ssh def self.action_ssh
Vagrant::Action::Builder.new.tap do |b| Vagrant::Action::Builder.new.tap do |b|

View File

@ -0,0 +1,48 @@
module VagrantPlugins
module ProviderVirtualBox
module Action
class Boot
def initialize(app, env)
@app = app
end
def call(env)
@env = env
# Start up the VM and wait for it to boot.
env[:ui].info I18n.t("vagrant.actions.vm.boot.booting")
env[:machine].provider.driver.start(@env[:machine].config.vm.boot_mode)
raise Errors::VMFailedToBoot if !wait_for_boot
@app.call(env)
end
def wait_for_boot
@env[:ui].info I18n.t("vagrant.actions.vm.boot.waiting")
@env[:machine].config.ssh.max_tries.to_i.times do |i|
if @env[:machine].communicate.ready?
@env[:ui].info I18n.t("vagrant.actions.vm.boot.ready")
return true
end
# Return true so that the vm_failed_to_boot error doesn't
# get shown
return true if @env[:interrupted]
# If the VM is not starting or running, something went wrong
# and we need to show a useful error.
state = @env[:machine].provider.state
raise Errors::VMFailedToRun if state != :starting && state != :running
sleep 2 if !@env["vagrant.test"]
end
@env[:ui].error I18n.t("vagrant.actions.vm.boot.failed")
false
end
end
end
end
end

View File

@ -0,0 +1,89 @@
require "vagrant/util/is_port_open"
module VagrantPlugins
module ProviderVirtualBox
module Action
class CheckPortCollisions
include Vagrant::Util::IsPortOpen
def initialize(app, env)
@app = app
end
def call(env)
# For the handlers...
@env = env
# Figure out how we handle port collisions. By default we error.
handler = env[:port_collision_handler] || :error
# Read our forwarded ports, if we have any, to override what
# we have configured.
current = {}
env[:machine].provider.driver.read_forwarded_ports.each do |nic, name, hostport, guestport|
current[name] = hostport.to_i
end
existing = env[:machine].provider.driver.read_used_ports
env[:machine].config.vm.forwarded_ports.each do |options|
# Use the proper port, whether that be the configured port or the
# port that is currently on use of the VM.
hostport = options[:hostport].to_i
hostport = current[options[:name]] if current.has_key?(options[:name])
if existing.include?(hostport) || is_port_open?("localhost", hostport)
# We have a collision! Handle it
send("handle_#{handler}".to_sym, options, existing)
end
end
@app.call(env)
end
# Handles a port collision by raising an exception.
def handle_error(options, existing_ports)
raise Vagrant::Errors::ForwardPortCollisionResume
end
# Handles a port collision by attempting to fix it.
def handle_correct(options, existing_ports)
# We need to keep this for messaging purposes
original_hostport = options[:hostport]
if !options[:auto]
# Auto fixing is disabled for this port forward, so we
# must throw an error so the user can fix it.
raise Vagrant::Errors::ForwardPortCollision,
:host_port => options[:hostport].to_s,
:guest_port => options[:guestport].to_s
end
# Get the auto port range and get rid of the used ports and
# ports which are being used in other forwards so we're just
# left with available ports.
range = @env[:machine].config.vm.auto_port_range.to_a
range -= @env[:machine].config.vm.forwarded_ports.collect { |opts| opts[:hostport].to_i }
range -= existing_ports
if range.empty?
raise Vagrant::Errors::ForwardPortAutolistEmpty,
:vm_name => @env[:machine].name,
:host_port => options[:hostport].to_s,
:guest_port => options[:guestport].to_s
end
# Set the port up to be the first one and add that port to
# the used list.
options[:hostport] = range.shift
existing_ports << options[:hostport]
# Notify the user
@env[:ui].info(I18n.t("vagrant.actions.vm.forward_ports.fixed_collision",
:host_port => original_hostport.to_s,
:guest_port => options[:guestport].to_s,
:new_port => options[:hostport]))
end
end
end
end
end

View File

@ -1,13 +1,13 @@
module Vagrant module VagrantPlugins
module Action module ProviderVirtualBox
module VM module Action
class Resume class Resume
def initialize(app, env) def initialize(app, env)
@app = app @app = app
end end
def call(env) def call(env)
if env[:vm].state == :saved if env[:machine].provider.state == :saved
env[:ui].info I18n.t("vagrant.actions.vm.resume.resuming") env[:ui].info I18n.t("vagrant.actions.vm.resume.resuming")
env[:action_runner].run(Boot, env) env[:action_runner].run(Boot, env)
end end