core: improve guest type detection
/cc @fgrehm - I figured you might be interested in this. :)
This commit is contained in:
parent
581841a195
commit
ba18d98d45
|
@ -300,6 +300,10 @@ module Vagrant
|
||||||
error_key(:guest_capability_not_found)
|
error_key(:guest_capability_not_found)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class GuestExplicitNotDetected < VagrantError
|
||||||
|
error_key(:guest_explicit_not_detected)
|
||||||
|
end
|
||||||
|
|
||||||
class GuestNotDetected < VagrantError
|
class GuestNotDetected < VagrantError
|
||||||
error_key(:guest_not_detected)
|
error_key(:guest_not_detected)
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,74 +39,23 @@ module Vagrant
|
||||||
def detect!
|
def detect!
|
||||||
@logger.info("Detect guest for machine: #{@machine}")
|
@logger.info("Detect guest for machine: #{@machine}")
|
||||||
|
|
||||||
# Get the mapping of guests with the most parents. We start searching
|
guest_name = @machine.config.vm.guest
|
||||||
# with the guests with the most parents first.
|
if guest_name
|
||||||
parent_count = {}
|
@logger.info("Using explicit config.vm.guest value: #{guest_name}")
|
||||||
@guests.each do |name, parts|
|
else
|
||||||
parent_count[name] = 0
|
# No explicit guest was specified, so autodetect it.
|
||||||
|
guest_name = autodetect_guest
|
||||||
parent = parts[1]
|
raise Errors::GuestNotDetected if !guest_name
|
||||||
while parent
|
|
||||||
parent_count[name] += 1
|
|
||||||
parent = @guests[parent]
|
|
||||||
parent = parent[1] if parent
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Now swap around the mapping so that it is a mapping of
|
if !@guests[guest_name]
|
||||||
# count to the actual list of guest names
|
# This can happen if config.vm.guest was specified with a value
|
||||||
parent_count_to_guests = {}
|
# that doesn't exist.
|
||||||
parent_count.each do |name, count|
|
raise Errors::GuestExplicitNotDetected, value: guest_name.to_s
|
||||||
parent_count_to_guests[count] ||= []
|
|
||||||
parent_count_to_guests[count] << name
|
|
||||||
end
|
end
|
||||||
|
|
||||||
catch(:guest_os) do
|
@name = guest_name
|
||||||
sorted_counts = parent_count_to_guests.keys.sort.reverse
|
@chain = guest_chain(@name)
|
||||||
sorted_counts.each do |count|
|
|
||||||
parent_count_to_guests[count].each do |name|
|
|
||||||
@logger.debug("Trying: #{name}")
|
|
||||||
guest_info = @guests[name]
|
|
||||||
guest = guest_info[0].new
|
|
||||||
|
|
||||||
# If a specific guest was specified, then attempt to use that
|
|
||||||
# guest no matter what. Otherwise, only use it if it was detected.
|
|
||||||
use_this_guest = false
|
|
||||||
if @machine.config.vm.guest.nil?
|
|
||||||
use_this_guest = guest.detect?(@machine)
|
|
||||||
else
|
|
||||||
use_this_guest = @machine.config.vm.guest.to_sym == name.to_sym
|
|
||||||
end
|
|
||||||
|
|
||||||
if use_this_guest
|
|
||||||
@logger.info("Detected: #{name}!")
|
|
||||||
@chain << [name, guest]
|
|
||||||
@name = name
|
|
||||||
|
|
||||||
# Build the proper chain of parents if there are any.
|
|
||||||
# This allows us to do "inheritance" of capabilities later
|
|
||||||
if guest_info[1]
|
|
||||||
parent_name = guest_info[1]
|
|
||||||
parent_info = @guests[parent_name]
|
|
||||||
while parent_info
|
|
||||||
@chain << [parent_name, parent_info[0].new]
|
|
||||||
parent_name = parent_info[1]
|
|
||||||
parent_info = @guests[parent_name]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@logger.info("Full guest chain: #{@chain.inspect}")
|
|
||||||
|
|
||||||
# Exit the search
|
|
||||||
throw :guest_os
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# We shouldn't reach this point. Ideally we would detect
|
|
||||||
# all operating systems.
|
|
||||||
raise Errors::GuestNotDetected if @chain.empty?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Tests whether the guest has the named capability.
|
# Tests whether the guest has the named capability.
|
||||||
|
@ -168,5 +117,75 @@ module Vagrant
|
||||||
|
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This autodetects the guest to use and returns the name of the guest.
|
||||||
|
# This returns nil if the guest type could not be autodetected.
|
||||||
|
#
|
||||||
|
# @return [Symbol]
|
||||||
|
def autodetect_guest
|
||||||
|
@logger.info("Autodetecting guest for machine: #{@machine}")
|
||||||
|
|
||||||
|
# Get the mapping of guests with the most parents. We start searching
|
||||||
|
# with the guests with the most parents first.
|
||||||
|
parent_count = {}
|
||||||
|
@guests.each do |name, parts|
|
||||||
|
parent_count[name] = 0
|
||||||
|
|
||||||
|
parent = parts[1]
|
||||||
|
while parent
|
||||||
|
parent_count[name] += 1
|
||||||
|
parent = @guests[parent]
|
||||||
|
parent = parent[1] if parent
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Now swap around the mapping so that it is a mapping of
|
||||||
|
# count to the actual list of guest names
|
||||||
|
parent_count_to_guests = {}
|
||||||
|
parent_count.each do |name, count|
|
||||||
|
parent_count_to_guests[count] ||= []
|
||||||
|
parent_count_to_guests[count] << name
|
||||||
|
end
|
||||||
|
|
||||||
|
sorted_counts = parent_count_to_guests.keys.sort.reverse
|
||||||
|
sorted_counts.each do |count|
|
||||||
|
parent_count_to_guests[count].each do |name|
|
||||||
|
@logger.debug("Trying: #{name}")
|
||||||
|
guest_info = @guests[name]
|
||||||
|
guest = guest_info[0].new
|
||||||
|
|
||||||
|
if guest.detect?(@machine)
|
||||||
|
@logger.info("Detected: #{name}!")
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# This returns the complete chain for the given guest.
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
def guest_chain(name)
|
||||||
|
guest_info = @guests[name]
|
||||||
|
guest = guest_info[0].new
|
||||||
|
chain = []
|
||||||
|
chain << [name, guest]
|
||||||
|
|
||||||
|
# Build the proper chain of parents if there are any.
|
||||||
|
# This allows us to do "inheritance" of capabilities later
|
||||||
|
if guest_info[1]
|
||||||
|
parent_name = guest_info[1]
|
||||||
|
parent_info = @guests[parent_name]
|
||||||
|
while parent_info
|
||||||
|
chain << [parent_name, parent_info[0].new]
|
||||||
|
parent_name = parent_info[1]
|
||||||
|
parent_info = @guests[parent_name]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return chain
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -366,6 +366,11 @@ en:
|
||||||
support that capability. This capability is required for your
|
support that capability. This capability is required for your
|
||||||
configuration of Vagrant. Please either reconfigure Vagrant to
|
configuration of Vagrant. Please either reconfigure Vagrant to
|
||||||
avoid this capability or fix the issue by creating the capability.
|
avoid this capability or fix the issue by creating the capability.
|
||||||
|
guest_explicit_not_detected: |-
|
||||||
|
The guest implementation explicitly specified in your Vagrantfile
|
||||||
|
("%{value}") could not be found. Please verify that the plugin is
|
||||||
|
installed which implements this guest and that the value you
|
||||||
|
used for `config.vm.guest` is correct.
|
||||||
guest_not_detected: |-
|
guest_not_detected: |-
|
||||||
The guest operating system of the machine could not be detected!
|
The guest operating system of the machine could not be detected!
|
||||||
Vagrant requires this knowledge to perform specific tasks such
|
Vagrant requires this knowledge to perform specific tasks such
|
||||||
|
|
|
@ -156,6 +156,15 @@ describe Vagrant::Guest do
|
||||||
subject.name.should == :bar
|
subject.name.should == :bar
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "raises an exception if the forced guest can't be found" do
|
||||||
|
register_guest(:foo, nil, true)
|
||||||
|
|
||||||
|
machine.config.vm.stub(:guest => :bar)
|
||||||
|
|
||||||
|
expect { subject.detect! }.
|
||||||
|
to raise_error(Vagrant::Errors::GuestExplicitNotDetected)
|
||||||
|
end
|
||||||
|
|
||||||
it "raises an exception if no guest can be detected" do
|
it "raises an exception if no guest can be detected" do
|
||||||
expect { subject.detect! }.
|
expect { subject.detect! }.
|
||||||
to raise_error(Vagrant::Errors::GuestNotDetected)
|
to raise_error(Vagrant::Errors::GuestNotDetected)
|
||||||
|
|
Loading…
Reference in New Issue