Properly resolve and load the guest class impl for Machines

This commit is contained in:
Mitchell Hashimoto 2012-08-12 18:35:19 -07:00
parent 28f341ec75
commit f9752d78d8
5 changed files with 115 additions and 9 deletions

View File

@ -129,8 +129,21 @@ module Vagrant
#
# @return [Object]
def guest
raise Errors::MachineGuestNotReady if !communicator.ready?
# XXX: Todo
raise Errors::MachineGuestNotReady if !communicate.ready?
# Load the initial guest.
guest = load_guest(config.vm.guest)
# Loop and distro dispatch while there are distros.
while true
distro = guest.distro_dispatch
break if !distro
guest = load_guest(distro)
end
# Return the result
guest
end
# This sets the unique ID associated with this machine. This will
@ -230,5 +243,32 @@ module Vagrant
def state
@provider.state
end
protected
# Given a guest name (such as `:windows`), this will load the associated
# guest implementation and return an instance.
#
# @param [Symbol] guest The name of the guest implementation.
# @return [Object]
def load_guest(guest)
@logger.info("Loading guest: #{guest}")
klass = nil
Vagrant.plugin("1").registered.each do |plugin|
if plugin.guest.has_key?(guest)
klass = plugin.guest[guest]
break
end
end
if klass.nil?
raise Errors::VMGuestError,
:_key => :unknown_type,
:guest => guest.to_s
end
return klass.new(self)
end
end
end

View File

@ -27,9 +27,8 @@ module Vagrant
# Vagrant can successfully SSH into the machine) to give the system a chance
# to determine the distro and return a distro-specific system.
#
# **Warning:** If a return value which subclasses from {Base} is
# returned, Vagrant will use it as the new system instance for the
# class.
# If this method returns nil, then this instance is assumed to be
# the most specific guest implementation.
def distro_dispatch
end

View File

@ -13,13 +13,13 @@ module VagrantPlugins
# attempt a graceful shutdown
if current_state == :running && !env["force"]
env[:ui].info I18n.t("vagrant.actions.vm.halt.graceful")
env[:vm].guest.halt
env[:machine].guest.halt
end
# If we're not powered off now, then force it
if env[:vm].state != :poweroff
if env[:machine].state != :poweroff
env[:ui].info I18n.t("vagrant.actions.vm.halt.force")
env[:vm].driver.halt
env[:machine].driver.halt
end
# Sleep for a second to verify that the VM properly

View File

@ -5,11 +5,23 @@ require "unit/support/isolated_environment"
shared_context "unit" do
before(:each) do
# State to store the list of registered plugins that we have to
# unregister later.
@_plugins = []
# Create a thing to store our temporary files so that they aren't
# unlinked right away.
@_temp_files = []
end
after(:each) do
# Unregister each of the plugins we have may have temporarily
# registered for the duration of this test.
@_plugins.each do |plugin|
plugin.unregister!
end
end
# This creates an isolated environment so that Vagrant doesn't
# muck around with your real system during unit tests.
#
@ -22,6 +34,20 @@ shared_context "unit" do
env
end
# This registers a Vagrant plugin for the duration of a single test.
# This will yield a new plugin class that you can then call the
# public plugin methods on.
#
# @yield [plugin] Yields the plugin class for you to call the public
# API that you need to.
def register_plugin
plugin = Class.new(Vagrant.plugin("1"))
plugin.name("Test Plugin #{plugin.inspect}")
yield plugin if block_given?
@_plugins << plugin
plugin
end
# This helper creates a temporary file and returns a Pathname
# object pointed to it.
#

View File

@ -199,7 +199,7 @@ describe Vagrant::Machine do
end
before(:each) do
instance.stub(:communicator).and_return(communicator)
instance.stub(:communicate).and_return(communicator)
end
it "should raise an exception if communication is not ready" do
@ -208,6 +208,47 @@ describe Vagrant::Machine do
expect { instance.guest }.
to raise_error(Vagrant::Errors::MachineGuestNotReady)
end
it "should return the configured guest" do
test_guest = Class.new(Vagrant.plugin("1", :guest))
register_plugin do |p|
p.guest(:test) { test_guest }
end
config.vm.guest = :test
result = instance.guest
result.should be_kind_of(test_guest)
end
it "should raise an exception if it can't find the configured guest" do
config.vm.guest = :bad
expect { instance.guest }.
to raise_error(Vagrant::Errors::VMGuestError)
end
it "should distro dispatch to the most specific guest" do
# Create the classes and dispatch the parent into the child
guest_parent = Class.new(Vagrant.plugin("1", :guest)) do
def distro_dispatch
:child
end
end
guest_child = Class.new(Vagrant.plugin("1", :guest))
# Register the classes
register_plugin do |p|
p.guest(:parent) { guest_parent }
p.guest(:child) { guest_child }
end
# Test that the result is the child
config.vm.guest = :parent
instance.guest.should be_kind_of(guest_child)
end
end
describe "setting the ID" do