Merge pull request #2947 from mitchellh/f-environment-refactor
Core refactor: "Vagrantfile" abstraction
This commit is contained in:
commit
2dac667544
|
@ -23,7 +23,8 @@ module Vagrant
|
||||||
@app = app
|
@app = app
|
||||||
|
|
||||||
env["package.files"] ||= {}
|
env["package.files"] ||= {}
|
||||||
env["package.output"] ||= env[:global_config].package.name
|
env["package.output"] ||= env[:machine].package.name
|
||||||
|
env["package.output"] ||= "package.box"
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
|
|
|
@ -8,11 +8,13 @@ require 'log4r'
|
||||||
|
|
||||||
require 'vagrant/util/file_mode'
|
require 'vagrant/util/file_mode'
|
||||||
require 'vagrant/util/platform'
|
require 'vagrant/util/platform'
|
||||||
|
require "vagrant/vagrantfile"
|
||||||
|
|
||||||
module Vagrant
|
module Vagrant
|
||||||
# Represents a single Vagrant environment. A "Vagrant environment" is
|
# A "Vagrant environment" represents a configuration of how Vagrant
|
||||||
# defined as basically a folder with a "Vagrantfile." This class allows
|
# should behave: data directories, working directory, UI output,
|
||||||
# access to the VMs, CLI, etc. all in the scope of this environment.
|
# etc. In day-to-day usage, every `vagrant` invocation typically
|
||||||
|
# leads to a single Vagrant environment.
|
||||||
class Environment
|
class Environment
|
||||||
# This is the current version that this version of Vagrant is
|
# This is the current version that this version of Vagrant is
|
||||||
# compatible with in the home directory.
|
# compatible with in the home directory.
|
||||||
|
@ -150,9 +152,24 @@ module Vagrant
|
||||||
"#<#{self.class}: #{@cwd}>"
|
"#<#{self.class}: #{@cwd}>"
|
||||||
end
|
end
|
||||||
|
|
||||||
#---------------------------------------------------------------
|
# Action runner for executing actions in the context of this environment.
|
||||||
# Helpers
|
#
|
||||||
#---------------------------------------------------------------
|
# @return [Action::Runner]
|
||||||
|
def action_runner
|
||||||
|
@action_runner ||= Action::Runner.new do
|
||||||
|
{
|
||||||
|
:action_runner => action_runner,
|
||||||
|
:box_collection => boxes,
|
||||||
|
:hook => method(:hook),
|
||||||
|
:host => host,
|
||||||
|
:gems_path => gems_path,
|
||||||
|
:home_path => home_path,
|
||||||
|
:root_path => root_path,
|
||||||
|
:tmp_path => tmp_path,
|
||||||
|
:ui => @ui
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Returns a list of machines that this environment is currently
|
# Returns a list of machines that this environment is currently
|
||||||
# managing that physically have been created.
|
# managing that physically have been created.
|
||||||
|
@ -218,6 +235,15 @@ module Vagrant
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Makes a call to the CLI with the given arguments as if they
|
||||||
|
# came from the real command line (sometimes they do!). An example:
|
||||||
|
#
|
||||||
|
# env.cli("package", "--vagrantfile", "Vagrantfile")
|
||||||
|
#
|
||||||
|
def cli(*args)
|
||||||
|
CLI.new(args.flatten, self).execute
|
||||||
|
end
|
||||||
|
|
||||||
# This returns the provider name for the default provider for this
|
# This returns the provider name for the default provider for this
|
||||||
# environment. The provider returned is currently hardcoded to "virtualbox"
|
# environment. The provider returned is currently hardcoded to "virtualbox"
|
||||||
# but one day should be a detected valid, best-case provider for this
|
# but one day should be a detected valid, best-case provider for this
|
||||||
|
@ -235,39 +261,25 @@ module Vagrant
|
||||||
@_boxes ||= BoxCollection.new(boxes_path, temp_dir_root: tmp_path)
|
@_boxes ||= BoxCollection.new(boxes_path, temp_dir_root: tmp_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
# This is the global config, comprised of loading configuration from
|
# Returns the {Config::Loader} that can be used to load Vagrantflies
|
||||||
# the default, home, and root Vagrantfiles. This configuration is only
|
# given the settings of this environment.
|
||||||
# really useful for reading the list of virtual machines, since each
|
|
||||||
# individual VM can override _most_ settings.
|
|
||||||
#
|
#
|
||||||
# This is lazy-loaded upon first use.
|
# @return [Config::Loader]
|
||||||
#
|
def config_loader
|
||||||
# @return [Object]
|
return @config_loader if @config_loader
|
||||||
def config_global
|
|
||||||
return @config_global if @config_global
|
|
||||||
|
|
||||||
@logger.info("Initializing config...")
|
|
||||||
|
|
||||||
home_vagrantfile = nil
|
home_vagrantfile = nil
|
||||||
root_vagrantfile = nil
|
root_vagrantfile = nil
|
||||||
home_vagrantfile = find_vagrantfile(home_path) if home_path
|
home_vagrantfile = find_vagrantfile(home_path) if home_path
|
||||||
root_vagrantfile = find_vagrantfile(root_path, @vagrantfile_name) if root_path
|
if root_path
|
||||||
|
root_vagrantfile = find_vagrantfile(root_path, @vagrantfile_name)
|
||||||
|
end
|
||||||
|
|
||||||
# Create the configuration loader and set the sources that are global.
|
@config_loader = Config::Loader.new(
|
||||||
# We use this to load the configuration, and the list of machines we are
|
Config::VERSIONS, Config::VERSIONS_ORDER)
|
||||||
# managing. Then, the actual individual configuration is loaded for
|
|
||||||
# each {#machine} call.
|
|
||||||
@config_loader = Config::Loader.new(Config::VERSIONS, Config::VERSIONS_ORDER)
|
|
||||||
@config_loader.set(:home, home_vagrantfile) if home_vagrantfile
|
@config_loader.set(:home, home_vagrantfile) if home_vagrantfile
|
||||||
@config_loader.set(:root, root_vagrantfile) if root_vagrantfile
|
@config_loader.set(:root, root_vagrantfile) if root_vagrantfile
|
||||||
|
@config_loader
|
||||||
# Make the initial call to get the "global" config. This is mostly
|
|
||||||
# only useful to get the list of machines that we are managing.
|
|
||||||
# Because of this, we ignore any warnings or errors.
|
|
||||||
@config_global, _ = @config_loader.load([:home, :root])
|
|
||||||
|
|
||||||
# Return the config
|
|
||||||
@config_global
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# This defines a hook point where plugin action hooks that are registered
|
# This defines a hook point where plugin action hooks that are registered
|
||||||
|
@ -285,201 +297,6 @@ module Vagrant
|
||||||
opts.delete(:runner).run(opts.delete(:callable), opts)
|
opts.delete(:runner).run(opts.delete(:callable), opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
# This returns a machine with the proper provider for this environment.
|
|
||||||
# The machine named by `name` must be in this environment.
|
|
||||||
#
|
|
||||||
# @param [Symbol] name Name of the machine (as configured in the
|
|
||||||
# Vagrantfile).
|
|
||||||
# @param [Symbol] provider The provider that this machine should be
|
|
||||||
# backed by.
|
|
||||||
# @param [Boolean] refresh If true, then if there is a cached version
|
|
||||||
# it is reloaded.
|
|
||||||
# @return [Machine]
|
|
||||||
def machine(name, provider, refresh=false)
|
|
||||||
@logger.info("Getting machine: #{name} (#{provider})")
|
|
||||||
|
|
||||||
# Compose the cache key of the name and provider, and return from
|
|
||||||
# the cache if we have that.
|
|
||||||
cache_key = [name, provider]
|
|
||||||
@machines ||= {}
|
|
||||||
if refresh
|
|
||||||
@logger.info("Refreshing machine (busting cache): #{name} (#{provider})")
|
|
||||||
@machines.delete(cache_key)
|
|
||||||
end
|
|
||||||
|
|
||||||
if @machines.has_key?(cache_key)
|
|
||||||
@logger.info("Returning cached machine: #{name} (#{provider})")
|
|
||||||
return @machines[cache_key]
|
|
||||||
end
|
|
||||||
|
|
||||||
@logger.info("Uncached load of machine.")
|
|
||||||
sub_vm = config_global.vm.defined_vms[name]
|
|
||||||
if !sub_vm
|
|
||||||
raise Errors::MachineNotFound, :name => name, :provider => provider
|
|
||||||
end
|
|
||||||
|
|
||||||
provider_plugin = Vagrant.plugin("2").manager.providers[provider]
|
|
||||||
if !provider_plugin
|
|
||||||
raise Errors::ProviderNotFound, :machine => name, :provider => provider
|
|
||||||
end
|
|
||||||
|
|
||||||
# Extra the provider class and options from the plugin data
|
|
||||||
provider_cls = provider_plugin[0]
|
|
||||||
provider_options = provider_plugin[1]
|
|
||||||
|
|
||||||
# Build the machine configuration. This requires two passes: The first pass
|
|
||||||
# loads in the machine sub-configuration. Since this can potentially
|
|
||||||
# define a new box to base the machine from, we then make a second pass
|
|
||||||
# with the box Vagrantfile (if it has one).
|
|
||||||
vm_config_key = "vm_#{name}".to_sym
|
|
||||||
@config_loader.set(vm_config_key, sub_vm.config_procs)
|
|
||||||
config, config_warnings, config_errors = \
|
|
||||||
@config_loader.load([:home, :root, vm_config_key])
|
|
||||||
|
|
||||||
# Determine the possible box formats for any boxes and find the box
|
|
||||||
box_formats = provider_options[:box_format] || provider
|
|
||||||
box = nil
|
|
||||||
|
|
||||||
# Set this variable in order to keep track of if the box changes
|
|
||||||
# too many times.
|
|
||||||
original_box = config.vm.box
|
|
||||||
box_changed = false
|
|
||||||
|
|
||||||
load_box_and_overrides = lambda do
|
|
||||||
box = nil
|
|
||||||
if config.vm.box
|
|
||||||
box = boxes.find(
|
|
||||||
config.vm.box, box_formats, config.vm.box_version)
|
|
||||||
end
|
|
||||||
|
|
||||||
# If a box was found, then we attempt to load the Vagrantfile for
|
|
||||||
# that box. We don't require a box since we allow providers to download
|
|
||||||
# boxes and so on.
|
|
||||||
if box
|
|
||||||
box_vagrantfile = find_vagrantfile(box.directory)
|
|
||||||
if box_vagrantfile
|
|
||||||
# The box has a custom Vagrantfile, so we load that into the config
|
|
||||||
# as well.
|
|
||||||
@logger.info("Box exists with Vagrantfile. Reloading machine config.")
|
|
||||||
box_config_key = "box_#{box.name}_#{box.provider}".to_sym
|
|
||||||
@config_loader.set(box_config_key, box_vagrantfile)
|
|
||||||
config, config_warnings, config_errors = \
|
|
||||||
@config_loader.load([box_config_key, :home, :root, vm_config_key])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# If there are provider overrides for the machine, then we run
|
|
||||||
# those as well.
|
|
||||||
provider_overrides = config.vm.get_provider_overrides(provider)
|
|
||||||
if provider_overrides.length > 0
|
|
||||||
@logger.info("Applying #{provider_overrides.length} provider overrides. Reloading config.")
|
|
||||||
provider_override_key = "vm_#{name}_#{config.vm.box}_#{provider}".to_sym
|
|
||||||
@config_loader.set(provider_override_key, provider_overrides)
|
|
||||||
config, config_warnings, config_errors = \
|
|
||||||
@config_loader.load([box_config_key, :home, :root, vm_config_key, provider_override_key])
|
|
||||||
end
|
|
||||||
|
|
||||||
if config.vm.box && original_box != config.vm.box
|
|
||||||
if box_changed
|
|
||||||
# We already changed boxes once, so report an error that a
|
|
||||||
# box is attempting to change boxes again.
|
|
||||||
raise Errors::BoxConfigChangingBox
|
|
||||||
end
|
|
||||||
|
|
||||||
# The box changed, probably due to the provider override. Let's
|
|
||||||
# run the configuration one more time with the new box.
|
|
||||||
@logger.info("Box changed to: #{config.vm.box}. Reloading configurations.")
|
|
||||||
original_box = config.vm.box
|
|
||||||
box_changed = true
|
|
||||||
|
|
||||||
# Recurse so that we reload all the configurations
|
|
||||||
load_box_and_overrides.call
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Load the box and overrides configuration
|
|
||||||
load_box_and_overrides.call
|
|
||||||
|
|
||||||
# Get the provider configuration from the final loaded configuration
|
|
||||||
provider_config = config.vm.get_provider_config(provider)
|
|
||||||
|
|
||||||
# Determine the machine data directory and pass it to the machine.
|
|
||||||
# XXX: Permissions error here.
|
|
||||||
machine_data_path = @local_data_path.join("machines/#{name}/#{provider}")
|
|
||||||
FileUtils.mkdir_p(machine_data_path)
|
|
||||||
|
|
||||||
# If there were warnings or errors we want to output them
|
|
||||||
if !config_warnings.empty? || !config_errors.empty?
|
|
||||||
# The color of the output depends on whether we have warnings
|
|
||||||
# or errors...
|
|
||||||
level = config_errors.empty? ? :warn : :error
|
|
||||||
output = Util::TemplateRenderer.render(
|
|
||||||
"config/messages",
|
|
||||||
:warnings => config_warnings,
|
|
||||||
:errors => config_errors).chomp
|
|
||||||
@ui.send(level, I18n.t("vagrant.general.config_upgrade_messages",
|
|
||||||
name: name,
|
|
||||||
:output => output))
|
|
||||||
|
|
||||||
# If we had errors, then we bail
|
|
||||||
raise Errors::ConfigUpgradeErrors if !config_errors.empty?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Create the machine and cache it for future calls. This will also
|
|
||||||
# return the machine from this method.
|
|
||||||
@machines[cache_key] = Machine.new(name, provider, provider_cls, provider_config,
|
|
||||||
provider_options, config, machine_data_path, box, self)
|
|
||||||
end
|
|
||||||
|
|
||||||
# This returns a list of the configured machines for this environment.
|
|
||||||
# Each of the names returned by this method is valid to be used with
|
|
||||||
# the {#machine} method.
|
|
||||||
#
|
|
||||||
# @return [Array<Symbol>] Configured machine names.
|
|
||||||
def machine_names
|
|
||||||
config_global.vm.defined_vm_keys.dup
|
|
||||||
end
|
|
||||||
|
|
||||||
# This returns the name of the machine that is the "primary." In the
|
|
||||||
# case of a single-machine environment, this is just the single machine
|
|
||||||
# name. In the case of a multi-machine environment, then this can
|
|
||||||
# potentially be nil if no primary machine is specified.
|
|
||||||
#
|
|
||||||
# @return [Symbol]
|
|
||||||
def primary_machine_name
|
|
||||||
# If it is a single machine environment, then return the name
|
|
||||||
return machine_names.first if machine_names.length == 1
|
|
||||||
|
|
||||||
# If it is a multi-machine environment, then return the primary
|
|
||||||
config_global.vm.defined_vms.each do |name, subvm|
|
|
||||||
return name if subvm.options[:primary]
|
|
||||||
end
|
|
||||||
|
|
||||||
# If no primary was specified, nil it is
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
# Unload the environment, running completion hooks. The environment
|
|
||||||
# should not be used after this (but CAN be, technically). It is
|
|
||||||
# recommended to always immediately set the variable to `nil` after
|
|
||||||
# running this so you can't accidentally run any more methods. Example:
|
|
||||||
#
|
|
||||||
# env.unload
|
|
||||||
# env = nil
|
|
||||||
#
|
|
||||||
def unload
|
|
||||||
hook(:environment_unload)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Makes a call to the CLI with the given arguments as if they
|
|
||||||
# came from the real command line (sometimes they do!). An example:
|
|
||||||
#
|
|
||||||
# env.cli("package", "--vagrantfile", "Vagrantfile")
|
|
||||||
#
|
|
||||||
def cli(*args)
|
|
||||||
CLI.new(args.flatten, self).execute
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the host object associated with this environment.
|
# Returns the host object associated with this environment.
|
||||||
#
|
#
|
||||||
# @return [Class]
|
# @return [Class]
|
||||||
|
@ -490,7 +307,7 @@ module Vagrant
|
||||||
# that shouldn't be valid anymore, but we respect it here by assuming
|
# that shouldn't be valid anymore, but we respect it here by assuming
|
||||||
# its old behavior. No need to deprecate this because I thin it is
|
# its old behavior. No need to deprecate this because I thin it is
|
||||||
# fairly harmless.
|
# fairly harmless.
|
||||||
host_klass = config_global.vagrant.host
|
host_klass = vagrantfile.config.vagrant.host
|
||||||
host_klass = nil if host_klass == :detect
|
host_klass = nil if host_klass == :detect
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
@ -516,46 +333,6 @@ module Vagrant
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Action runner for executing actions in the context of this environment.
|
|
||||||
#
|
|
||||||
# @return [Action::Runner]
|
|
||||||
def action_runner
|
|
||||||
@action_runner ||= Action::Runner.new do
|
|
||||||
{
|
|
||||||
:action_runner => action_runner,
|
|
||||||
:box_collection => boxes,
|
|
||||||
:global_config => config_global,
|
|
||||||
:hook => method(:hook),
|
|
||||||
:host => host,
|
|
||||||
:gems_path => gems_path,
|
|
||||||
:home_path => home_path,
|
|
||||||
:root_path => root_path,
|
|
||||||
:tmp_path => tmp_path,
|
|
||||||
:ui => @ui
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# The root path is the path where the top-most (loaded last)
|
|
||||||
# Vagrantfile resides. It can be considered the project root for
|
|
||||||
# this environment.
|
|
||||||
#
|
|
||||||
# @return [String]
|
|
||||||
def root_path
|
|
||||||
return @root_path if defined?(@root_path)
|
|
||||||
|
|
||||||
root_finder = lambda do |path|
|
|
||||||
# Note: To remain compatible with Ruby 1.8, we have to use
|
|
||||||
# a `find` here instead of an `each`.
|
|
||||||
vf = find_vagrantfile(path, @vagrantfile_name)
|
|
||||||
return path if vf
|
|
||||||
return nil if path.root? || !File.exist?(path)
|
|
||||||
root_finder.call(path.parent)
|
|
||||||
end
|
|
||||||
|
|
||||||
@root_path = root_finder.call(cwd)
|
|
||||||
end
|
|
||||||
|
|
||||||
# This returns the path which Vagrant uses to determine the location
|
# This returns the path which Vagrant uses to determine the location
|
||||||
# of the file lock. This is specific to each operating system.
|
# of the file lock. This is specific to each operating system.
|
||||||
def lock_path
|
def lock_path
|
||||||
|
@ -589,6 +366,116 @@ module Vagrant
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This returns a machine with the proper provider for this environment.
|
||||||
|
# The machine named by `name` must be in this environment.
|
||||||
|
#
|
||||||
|
# @param [Symbol] name Name of the machine (as configured in the
|
||||||
|
# Vagrantfile).
|
||||||
|
# @param [Symbol] provider The provider that this machine should be
|
||||||
|
# backed by.
|
||||||
|
# @param [Boolean] refresh If true, then if there is a cached version
|
||||||
|
# it is reloaded.
|
||||||
|
# @return [Machine]
|
||||||
|
def machine(name, provider, refresh=false)
|
||||||
|
@logger.info("Getting machine: #{name} (#{provider})")
|
||||||
|
|
||||||
|
# Compose the cache key of the name and provider, and return from
|
||||||
|
# the cache if we have that.
|
||||||
|
cache_key = [name, provider]
|
||||||
|
@machines ||= {}
|
||||||
|
if refresh
|
||||||
|
@logger.info("Refreshing machine (busting cache): #{name} (#{provider})")
|
||||||
|
@machines.delete(cache_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
if @machines.has_key?(cache_key)
|
||||||
|
@logger.info("Returning cached machine: #{name} (#{provider})")
|
||||||
|
return @machines[cache_key]
|
||||||
|
end
|
||||||
|
|
||||||
|
@logger.info("Uncached load of machine.")
|
||||||
|
|
||||||
|
# Determine the machine data directory and pass it to the machine.
|
||||||
|
# XXX: Permissions error here.
|
||||||
|
machine_data_path = @local_data_path.join(
|
||||||
|
"machines/#{name}/#{provider}")
|
||||||
|
FileUtils.mkdir_p(machine_data_path)
|
||||||
|
|
||||||
|
# Create the machine and cache it for future calls. This will also
|
||||||
|
# return the machine from this method.
|
||||||
|
@machines[cache_key] = vagrantfile.machine(
|
||||||
|
name, provider, boxes, machine_data_path, self)
|
||||||
|
end
|
||||||
|
|
||||||
|
# This returns a list of the configured machines for this environment.
|
||||||
|
# Each of the names returned by this method is valid to be used with
|
||||||
|
# the {#machine} method.
|
||||||
|
#
|
||||||
|
# @return [Array<Symbol>] Configured machine names.
|
||||||
|
def machine_names
|
||||||
|
vagrantfile.machine_names
|
||||||
|
end
|
||||||
|
|
||||||
|
# This returns the name of the machine that is the "primary." In the
|
||||||
|
# case of a single-machine environment, this is just the single machine
|
||||||
|
# name. In the case of a multi-machine environment, then this can
|
||||||
|
# potentially be nil if no primary machine is specified.
|
||||||
|
#
|
||||||
|
# @return [Symbol]
|
||||||
|
def primary_machine_name
|
||||||
|
vagrantfile.primary_machine_name
|
||||||
|
end
|
||||||
|
|
||||||
|
# The root path is the path where the top-most (loaded last)
|
||||||
|
# Vagrantfile resides. It can be considered the project root for
|
||||||
|
# this environment.
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
def root_path
|
||||||
|
return @root_path if defined?(@root_path)
|
||||||
|
|
||||||
|
root_finder = lambda do |path|
|
||||||
|
# Note: To remain compatible with Ruby 1.8, we have to use
|
||||||
|
# a `find` here instead of an `each`.
|
||||||
|
vf = find_vagrantfile(path, @vagrantfile_name)
|
||||||
|
return path if vf
|
||||||
|
return nil if path.root? || !File.exist?(path)
|
||||||
|
root_finder.call(path.parent)
|
||||||
|
end
|
||||||
|
|
||||||
|
@root_path = root_finder.call(cwd)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Unload the environment, running completion hooks. The environment
|
||||||
|
# should not be used after this (but CAN be, technically). It is
|
||||||
|
# recommended to always immediately set the variable to `nil` after
|
||||||
|
# running this so you can't accidentally run any more methods. Example:
|
||||||
|
#
|
||||||
|
# env.unload
|
||||||
|
# env = nil
|
||||||
|
#
|
||||||
|
def unload
|
||||||
|
hook(:environment_unload)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Represents the default Vagrantfile, or the Vagrantfile that is
|
||||||
|
# in the working directory or a parent of the working directory
|
||||||
|
# of this environment.
|
||||||
|
#
|
||||||
|
# The existence of this function is primarily a convenience. There
|
||||||
|
# is nothing stopping you from instantiating your own {Vagrantfile}
|
||||||
|
# and loading machines in any way you see fit. Typical behavior of
|
||||||
|
# Vagrant, however, loads this Vagrantfile.
|
||||||
|
#
|
||||||
|
# This Vagrantfile is comprised of two major sources: the Vagrantfile
|
||||||
|
# in the user's home directory as well as the "root" Vagrantfile or
|
||||||
|
# the Vagrantfile in the working directory (or parent).
|
||||||
|
#
|
||||||
|
# @return [Vagrantfile]
|
||||||
|
def vagrantfile
|
||||||
|
@vagrantfile ||= Vagrantfile.new(config_loader, [:home, :root])
|
||||||
|
end
|
||||||
|
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
# Load Methods
|
# Load Methods
|
||||||
#---------------------------------------------------------------
|
#---------------------------------------------------------------
|
||||||
|
|
|
@ -34,7 +34,7 @@ module Vagrant
|
||||||
|
|
||||||
# Name of the machine. This is assigned by the Vagrantfile.
|
# Name of the machine. This is assigned by the Vagrantfile.
|
||||||
#
|
#
|
||||||
# @return [String]
|
# @return [Symbol]
|
||||||
attr_reader :name
|
attr_reader :name
|
||||||
|
|
||||||
# The provider backing this machine.
|
# The provider backing this machine.
|
||||||
|
@ -62,6 +62,11 @@ module Vagrant
|
||||||
# @return [UI]
|
# @return [UI]
|
||||||
attr_reader :ui
|
attr_reader :ui
|
||||||
|
|
||||||
|
# The Vagrantfile that this machine is attached to.
|
||||||
|
#
|
||||||
|
# @return [Vagrantfile]
|
||||||
|
attr_reader :vagrantfile
|
||||||
|
|
||||||
# Initialize a new machine.
|
# Initialize a new machine.
|
||||||
#
|
#
|
||||||
# @param [String] name Name of the virtual machine.
|
# @param [String] name Name of the virtual machine.
|
||||||
|
@ -77,7 +82,7 @@ module Vagrant
|
||||||
# @param [Box] box The box that is backing this virtual machine.
|
# @param [Box] box The box that is backing this virtual machine.
|
||||||
# @param [Environment] env The environment that this machine is a
|
# @param [Environment] env The environment that this machine is a
|
||||||
# part of.
|
# part of.
|
||||||
def initialize(name, provider_name, provider_cls, provider_config, provider_options, config, data_dir, box, env, base=false)
|
def initialize(name, provider_name, provider_cls, provider_config, provider_options, config, data_dir, box, env, vagrantfile, base=false)
|
||||||
@logger = Log4r::Logger.new("vagrant::machine")
|
@logger = Log4r::Logger.new("vagrant::machine")
|
||||||
@logger.info("Initializing machine: #{name}")
|
@logger.info("Initializing machine: #{name}")
|
||||||
@logger.info(" - Provider: #{provider_cls}")
|
@logger.info(" - Provider: #{provider_cls}")
|
||||||
|
@ -88,6 +93,7 @@ module Vagrant
|
||||||
@config = config
|
@config = config
|
||||||
@data_dir = data_dir
|
@data_dir = data_dir
|
||||||
@env = env
|
@env = env
|
||||||
|
@vagrantfile = vagrantfile
|
||||||
@guest = Guest.new(
|
@guest = Guest.new(
|
||||||
self,
|
self,
|
||||||
Vagrant.plugin("2").manager.guests,
|
Vagrant.plugin("2").manager.guests,
|
||||||
|
|
|
@ -0,0 +1,233 @@
|
||||||
|
require "vagrant/util/template_renderer"
|
||||||
|
|
||||||
|
module Vagrant
|
||||||
|
# This class provides a way to load and access the contents
|
||||||
|
# of a Vagrantfile.
|
||||||
|
#
|
||||||
|
# This class doesn't actually load Vagrantfiles, parse them,
|
||||||
|
# merge them, etc. That is the job of {Config::Loader}. This
|
||||||
|
# class, on the other hand, has higher-level operations on
|
||||||
|
# a loaded Vagrantfile such as looking up the defined machines,
|
||||||
|
# loading the configuration of a specific machine/provider combo,
|
||||||
|
# etc.
|
||||||
|
class Vagrantfile
|
||||||
|
# This is the configuration loaded as-is given the loader and
|
||||||
|
# keys to #initialize.
|
||||||
|
attr_reader :config
|
||||||
|
|
||||||
|
# Initializes by loading a Vagrantfile.
|
||||||
|
#
|
||||||
|
# @param [Config::Loader] loader Configuration loader that should
|
||||||
|
# already be configured with the proper Vagrantflie locations.
|
||||||
|
# This usually comes from {Vagrant::Environment}
|
||||||
|
# @param [Array<Symbol>] keys The Vagrantfiles to load and the
|
||||||
|
# order to load them in (keys within the loader).
|
||||||
|
def initialize(loader, keys)
|
||||||
|
@keys = keys
|
||||||
|
@loader = loader
|
||||||
|
@config, _ = loader.load(keys)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns a {Machine} for the given name and provider that
|
||||||
|
# is represented by this Vagrantfile.
|
||||||
|
#
|
||||||
|
# @param [Symbol] name Name of the machine.
|
||||||
|
# @param [Symbol] provider The provider the machine should
|
||||||
|
# be backed by (required for provider overrides).
|
||||||
|
# @param [BoxCollection] boxes BoxCollection to look up the
|
||||||
|
# box Vagrantfile.
|
||||||
|
# @param [Pathname] data_path Path where local machine data
|
||||||
|
# can be stored.
|
||||||
|
# @param [Environment] env The environment running this machine
|
||||||
|
# @return [Machine]
|
||||||
|
def machine(name, provider, boxes, data_path, env)
|
||||||
|
# Load the configuration for the machine
|
||||||
|
results = machine_config(name, provider, boxes)
|
||||||
|
box = results[:box]
|
||||||
|
config = results[:config]
|
||||||
|
config_errors = results[:config_errors]
|
||||||
|
config_warnings = results[:config_warnings]
|
||||||
|
provider_cls = results[:provider_cls]
|
||||||
|
provider_options = results[:provider_options]
|
||||||
|
|
||||||
|
# If there were warnings or errors we want to output them
|
||||||
|
if !config_warnings.empty? || !config_errors.empty?
|
||||||
|
# The color of the output depends on whether we have warnings
|
||||||
|
# or errors...
|
||||||
|
level = config_errors.empty? ? :warn : :error
|
||||||
|
output = Util::TemplateRenderer.render(
|
||||||
|
"config/messages",
|
||||||
|
:warnings => config_warnings,
|
||||||
|
:errors => config_errors).chomp
|
||||||
|
env.ui.send(level, I18n.t("vagrant.general.config_upgrade_messages",
|
||||||
|
name: name,
|
||||||
|
output: output))
|
||||||
|
|
||||||
|
# If we had errors, then we bail
|
||||||
|
raise Errors::ConfigUpgradeErrors if !config_errors.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get the provider configuration from the final loaded configuration
|
||||||
|
provider_config = config.vm.get_provider_config(provider)
|
||||||
|
|
||||||
|
# Create the machine and cache it for future calls. This will also
|
||||||
|
# return the machine from this method.
|
||||||
|
return Machine.new(name, provider, provider_cls, provider_config,
|
||||||
|
provider_options, config, data_path, box, env, self)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the configuration for a single machine.
|
||||||
|
#
|
||||||
|
# When loading a box Vagrantfile, it will be prepended to the
|
||||||
|
# key order specified when initializing this class. Sub-machine
|
||||||
|
# and provider-specific overrides are appended at the end. The
|
||||||
|
# actual order is:
|
||||||
|
#
|
||||||
|
# - box
|
||||||
|
# - keys specified for #initialize
|
||||||
|
# - sub-machine
|
||||||
|
# - provider
|
||||||
|
#
|
||||||
|
# The return value is a hash with the following keys (symbols)
|
||||||
|
# and values:
|
||||||
|
#
|
||||||
|
# - box: the {Box} backing the machine
|
||||||
|
# - config: the actual configuration
|
||||||
|
# - config_errors: list of errors, if any
|
||||||
|
# - config_warnings: list of warnings, if any
|
||||||
|
# - provider_cls: class of the provider backing the machine
|
||||||
|
# - provider_options: options for the provider
|
||||||
|
#
|
||||||
|
# @param [Symbol] name Name of the machine.
|
||||||
|
# @param [Symbol] provider The provider the machine should
|
||||||
|
# be backed by (required for provider overrides).
|
||||||
|
# @param [BoxCollection] boxes BoxCollection to look up the
|
||||||
|
# box Vagrantfile.
|
||||||
|
# @return [Hash<Symbol, Object>] Various configuration parameters for a
|
||||||
|
# machine. See the main documentation body for more info.
|
||||||
|
def machine_config(name, provider, boxes)
|
||||||
|
keys = @keys.dup
|
||||||
|
|
||||||
|
sub_machine = @config.vm.defined_vms[name]
|
||||||
|
if !sub_machine
|
||||||
|
raise Errors::MachineNotFound,
|
||||||
|
:name => name, :provider => provider
|
||||||
|
end
|
||||||
|
|
||||||
|
provider_plugin = Vagrant.plugin("2").manager.providers[provider]
|
||||||
|
if !provider_plugin
|
||||||
|
raise Errors::ProviderNotFound,
|
||||||
|
:machine => name, :provider => provider
|
||||||
|
end
|
||||||
|
|
||||||
|
provider_cls = provider_plugin[0]
|
||||||
|
provider_options = provider_plugin[1]
|
||||||
|
box_formats = provider_options[:box_format] || provider
|
||||||
|
|
||||||
|
# Add the sub-machine configuration to the loader and keys
|
||||||
|
vm_config_key = "#{object_id}_machine_#{name}"
|
||||||
|
@loader.set(vm_config_key, sub_machine.config_procs)
|
||||||
|
keys << vm_config_key
|
||||||
|
|
||||||
|
# Load once so that we can get the proper box value
|
||||||
|
config, config_warnings, config_errors = @loader.load(keys)
|
||||||
|
|
||||||
|
# Track the original box so we know if we changed
|
||||||
|
box = nil
|
||||||
|
original_box = config.vm.box
|
||||||
|
|
||||||
|
# The proc below loads the box and provider overrides. This is
|
||||||
|
# in a proc because it may have to recurse if the provider override
|
||||||
|
# changes the box.
|
||||||
|
load_box_proc = lambda do
|
||||||
|
local_keys = keys.dup
|
||||||
|
|
||||||
|
# Load the box Vagrantfile, if there is one
|
||||||
|
if config.vm.box
|
||||||
|
box = boxes.find(config.vm.box, box_formats, config.vm.box_version)
|
||||||
|
if box
|
||||||
|
box_vagrantfile = find_vagrantfile(box.directory)
|
||||||
|
if box_vagrantfile
|
||||||
|
box_config_key =
|
||||||
|
"#{boxes.object_id}_#{box.name}_#{box.provider}".to_sym
|
||||||
|
@loader.set(box_config_key, box_vagrantfile)
|
||||||
|
local_keys.unshift(box_config_key)
|
||||||
|
config, config_warnings, config_errors = @loader.load(local_keys)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Load provider overrides
|
||||||
|
provider_overrides = config.vm.get_provider_overrides(provider)
|
||||||
|
if !provider_overrides.empty?
|
||||||
|
config_key =
|
||||||
|
"#{object_id}_vm_#{name}_#{config.vm.box}_#{provider}".to_sym
|
||||||
|
@loader.set(config_key, provider_overrides)
|
||||||
|
local_keys << config_key
|
||||||
|
config, config_warnings, config_errors = @loader.load(local_keys)
|
||||||
|
end
|
||||||
|
|
||||||
|
# If the box changed, then we need to reload
|
||||||
|
if original_box != config.vm.box
|
||||||
|
# TODO: infinite loop protection?
|
||||||
|
|
||||||
|
original_box = config.vm.box
|
||||||
|
load_box_proc.call
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Load the box and provider overrides
|
||||||
|
load_box_proc.call
|
||||||
|
|
||||||
|
return {
|
||||||
|
box: box,
|
||||||
|
provider_cls: provider_cls,
|
||||||
|
provider_options: provider_options,
|
||||||
|
config: config,
|
||||||
|
config_warnings: config_warnings,
|
||||||
|
config_errors: config_errors,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns a list of the machines that are defined within this
|
||||||
|
# Vagrantfile.
|
||||||
|
#
|
||||||
|
# @return [Array<Symbol>]
|
||||||
|
def machine_names
|
||||||
|
@config.vm.defined_vm_keys.dup
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the name of the machine that is designated as the
|
||||||
|
# "primary."
|
||||||
|
#
|
||||||
|
# In the case of a single-machine environment, this is just the
|
||||||
|
# single machine name. In the case of a multi-machine environment,
|
||||||
|
# then this is the machine that is marked as primary, or nil if
|
||||||
|
# no primary machine was specified.
|
||||||
|
#
|
||||||
|
# @return [Symbol]
|
||||||
|
def primary_machine_name
|
||||||
|
# If it is a single machine environment, then return the name
|
||||||
|
return machine_names.first if machine_names.length == 1
|
||||||
|
|
||||||
|
# If it is a multi-machine environment, then return the primary
|
||||||
|
@config.vm.defined_vms.each do |name, subvm|
|
||||||
|
return name if subvm.options[:primary]
|
||||||
|
end
|
||||||
|
|
||||||
|
# If no primary was specified, nil it is
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def find_vagrantfile(search_path)
|
||||||
|
["Vagrantfile", "vagrantfile"].each do |vagrantfile|
|
||||||
|
current_path = search_path.join(vagrantfile)
|
||||||
|
return current_path if current_path.file?
|
||||||
|
end
|
||||||
|
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -31,7 +31,7 @@ module VagrantPlugins
|
||||||
raise Vagrant::Errors::BoxNotFound, :name => box_name, :provider => box_provider if !box
|
raise Vagrant::Errors::BoxNotFound, :name => box_name, :provider => box_provider if !box
|
||||||
|
|
||||||
# Repackage the box
|
# Repackage the box
|
||||||
output_name = @env.config_global.package.name || "package.box"
|
output_name = @env.vagrantfile.config.package.name || "package.box"
|
||||||
output_path = Pathname.new(File.expand_path(output_name, FileUtils.pwd))
|
output_path = Pathname.new(File.expand_path(output_name, FileUtils.pwd))
|
||||||
box.repackage(output_path)
|
box.repackage(output_path)
|
||||||
|
|
||||||
|
|
|
@ -59,9 +59,9 @@ module VagrantPlugins
|
||||||
vm = Vagrant::Machine.new(
|
vm = Vagrant::Machine.new(
|
||||||
options[:base],
|
options[:base],
|
||||||
:virtualbox, provider[0], nil, provider[1],
|
:virtualbox, provider[0], nil, provider[1],
|
||||||
@env.config_global,
|
@env.vagrantfile.config,
|
||||||
nil, nil,
|
nil, nil,
|
||||||
@env, true)
|
@env, @env.vagrantfile, true)
|
||||||
@logger.debug("Packaging base VM: #{vm.name}")
|
@logger.debug("Packaging base VM: #{vm.name}")
|
||||||
package_vm(vm, options)
|
package_vm(vm, options)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,30 +1,25 @@
|
||||||
require_relative "../base"
|
require_relative "../base"
|
||||||
|
|
||||||
describe VagrantPlugins::ProviderVirtualBox::Action::PrepareNFSValidIds do
|
describe VagrantPlugins::ProviderVirtualBox::Action::PrepareNFSValidIds do
|
||||||
|
include_context "unit"
|
||||||
include_context "virtualbox"
|
include_context "virtualbox"
|
||||||
|
|
||||||
let(:machine) {
|
let(:iso_env) do
|
||||||
environment = Vagrant::Environment.new
|
# We have to create a Vagrantfile so there is a root path
|
||||||
provider = :virtualbox
|
env = isolated_environment
|
||||||
provider_cls, provider_options = Vagrant.plugin("2").manager.providers[provider]
|
env.vagrantfile("")
|
||||||
provider_config = Vagrant.plugin("2").manager.provider_configs[provider]
|
env.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
Vagrant::Machine.new(
|
let(:machine) do
|
||||||
'test_machine',
|
iso_env.machine(iso_env.machine_names[0], :dummy).tap do |m|
|
||||||
provider,
|
m.provider.stub(driver: driver)
|
||||||
provider_cls,
|
end
|
||||||
provider_config,
|
end
|
||||||
provider_options,
|
|
||||||
environment.config_global,
|
|
||||||
Pathname('data_dir'),
|
|
||||||
double('box'),
|
|
||||||
environment
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let(:env) {{ machine: machine }}
|
let(:env) {{ machine: machine }}
|
||||||
let(:app) { lambda { |*args| }}
|
let(:app) { lambda { |*args| }}
|
||||||
let(:driver) { env[:machine].provider.driver }
|
let(:driver) { double("driver") }
|
||||||
|
|
||||||
subject { described_class.new(app, env) }
|
subject { described_class.new(app, env) }
|
||||||
|
|
||||||
|
|
|
@ -833,7 +833,7 @@ VF
|
||||||
end
|
end
|
||||||
|
|
||||||
env = environment.create_vagrant_env
|
env = environment.create_vagrant_env
|
||||||
env.config_global.ssh.port.should == 200
|
env.vagrantfile.config.ssh.port.should == 200
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should load from a custom Vagrantfile" do
|
it "should load from a custom Vagrantfile" do
|
||||||
|
@ -846,7 +846,7 @@ VF
|
||||||
end
|
end
|
||||||
|
|
||||||
env = environment.create_vagrant_env(:vagrantfile_name => "non_standard_name")
|
env = environment.create_vagrant_env(:vagrantfile_name => "non_standard_name")
|
||||||
env.config_global.ssh.port.should == 200
|
env.vagrantfile.config.ssh.port.should == 200
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should load from a custom Vagrantfile specified by env var" do
|
it "should load from a custom Vagrantfile specified by env var" do
|
||||||
|
@ -862,7 +862,7 @@ VF
|
||||||
environment.create_vagrant_env
|
environment.create_vagrant_env
|
||||||
end
|
end
|
||||||
|
|
||||||
env.config_global.ssh.port.should == 400
|
env.vagrantfile.config.ssh.port.should == 400
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ describe Vagrant::Machine do
|
||||||
let(:provider_name) { :test }
|
let(:provider_name) { :test }
|
||||||
let(:provider_options) { {} }
|
let(:provider_options) { {} }
|
||||||
let(:box) { Object.new }
|
let(:box) { Object.new }
|
||||||
let(:config) { env.config_global }
|
let(:config) { env.vagrantfile.config }
|
||||||
let(:data_dir) { Pathname.new(Dir.mktmpdir("vagrant")) }
|
let(:data_dir) { Pathname.new(Dir.mktmpdir("vagrant")) }
|
||||||
let(:env) do
|
let(:env) do
|
||||||
# We need to create a Vagrantfile so that this test environment
|
# We need to create a Vagrantfile so that this test environment
|
||||||
|
@ -41,7 +41,8 @@ describe Vagrant::Machine do
|
||||||
# Returns a new instance with the test data
|
# Returns a new instance with the test data
|
||||||
def new_instance
|
def new_instance
|
||||||
described_class.new(name, provider_name, provider_cls, provider_config,
|
described_class.new(name, provider_name, provider_cls, provider_config,
|
||||||
provider_options, config, data_dir, box, env)
|
provider_options, config, data_dir, box,
|
||||||
|
env, env.vagrantfile)
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "initialization" do
|
describe "initialization" do
|
||||||
|
@ -77,7 +78,8 @@ describe Vagrant::Machine do
|
||||||
# Initialize a new machine and verify that we properly receive
|
# Initialize a new machine and verify that we properly receive
|
||||||
# the machine we expect.
|
# the machine we expect.
|
||||||
instance = described_class.new(name, provider_name, provider_cls, provider_config,
|
instance = described_class.new(name, provider_name, provider_cls, provider_config,
|
||||||
provider_options, config, data_dir, box, env)
|
provider_options, config, data_dir, box,
|
||||||
|
env, env.vagrantfile)
|
||||||
received_machine.should eql(instance)
|
received_machine.should eql(instance)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -110,6 +112,12 @@ describe Vagrant::Machine do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should have the vagrantfile" do
|
||||||
|
provider_init_test do |machine|
|
||||||
|
expect(machine.vagrantfile).to equal(env.vagrantfile)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "should have access to the ID" do
|
it "should have access to the ID" do
|
||||||
# Stub this because #id= calls it.
|
# Stub this because #id= calls it.
|
||||||
provider.stub(:machine_id_changed)
|
provider.stub(:machine_id_changed)
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
require File.expand_path("../../../../base", __FILE__)
|
require File.expand_path("../../../../base", __FILE__)
|
||||||
|
|
||||||
describe Vagrant::Plugin::V2::Plugin do
|
describe Vagrant::Plugin::V2::Plugin do
|
||||||
after(:each) do
|
before do
|
||||||
# We want to make sure that the registered plugins remains empty
|
described_class.stub(manager: Vagrant::Plugin::V2::Manager.new)
|
||||||
# after each test.
|
|
||||||
described_class.manager.reset!
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should be able to set and get the name" do
|
it "should be able to set and get the name" do
|
||||||
|
|
|
@ -0,0 +1,324 @@
|
||||||
|
require File.expand_path("../../base", __FILE__)
|
||||||
|
|
||||||
|
require "pathname"
|
||||||
|
require "tmpdir"
|
||||||
|
|
||||||
|
require "vagrant/vagrantfile"
|
||||||
|
|
||||||
|
describe Vagrant::Vagrantfile do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:keys) { [] }
|
||||||
|
let(:loader) {
|
||||||
|
Vagrant::Config::Loader.new(
|
||||||
|
Vagrant::Config::VERSIONS, Vagrant::Config::VERSIONS_ORDER)
|
||||||
|
}
|
||||||
|
|
||||||
|
subject { described_class.new(loader, keys) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
keys << :test
|
||||||
|
end
|
||||||
|
|
||||||
|
def configure(&block)
|
||||||
|
loader.set(:test, [["2", block]])
|
||||||
|
end
|
||||||
|
|
||||||
|
# A helper to register a provider for use in tests.
|
||||||
|
def register_provider(name, config_class=nil, options=nil)
|
||||||
|
provider_cls = Class.new(Vagrant.plugin("2", :provider))
|
||||||
|
|
||||||
|
register_plugin("2") do |p|
|
||||||
|
p.provider(name, options) { provider_cls }
|
||||||
|
|
||||||
|
if config_class
|
||||||
|
p.config(name, :provider) { config_class }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
provider_cls
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#config" do
|
||||||
|
it "exposes the global configuration" do
|
||||||
|
configure do |config|
|
||||||
|
config.vm.box = "what"
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(subject.config.vm.box).to eq("what")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#machine" do
|
||||||
|
let(:boxes) { Vagrant::BoxCollection.new(iso_env.boxes_dir) }
|
||||||
|
let(:data_path) { Pathname.new(Dir.mktmpdir) }
|
||||||
|
let(:env) { iso_env.create_vagrant_env }
|
||||||
|
let(:iso_env) { isolated_environment }
|
||||||
|
let(:vagrantfile) { described_class.new(loader, keys) }
|
||||||
|
|
||||||
|
subject { vagrantfile.machine(:default, :foo, boxes, data_path, env) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
@foo_config_cls = Class.new(Vagrant.plugin("2", "config")) do
|
||||||
|
attr_accessor :value
|
||||||
|
end
|
||||||
|
|
||||||
|
@provider_cls = register_provider("foo", @foo_config_cls)
|
||||||
|
|
||||||
|
configure do |config|
|
||||||
|
config.vm.box = "foo"
|
||||||
|
config.vm.provider "foo" do |p|
|
||||||
|
p.value = "rawr"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
iso_env.box3("foo", "1.0", :foo, vagrantfile: <<-VF)
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.ssh.port = 123
|
||||||
|
end
|
||||||
|
VF
|
||||||
|
end
|
||||||
|
|
||||||
|
its(:data_dir) { should eq(data_path) }
|
||||||
|
its(:env) { should equal(env) }
|
||||||
|
its(:name) { should eq(:default) }
|
||||||
|
its(:provider) { should be_kind_of(@provider_cls) }
|
||||||
|
its(:provider_name) { should eq(:foo) }
|
||||||
|
its(:vagrantfile) { should equal(vagrantfile) }
|
||||||
|
|
||||||
|
it "has the proper box" do
|
||||||
|
expect(subject.box.name).to eq("foo")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "has the valid configuration" do
|
||||||
|
expect(subject.config.vm.box).to eq("foo")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "loads the provider-specific configuration" do
|
||||||
|
expect(subject.provider_config).to be_kind_of(@foo_config_cls)
|
||||||
|
expect(subject.provider_config.value).to eq("rawr")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#machine_config" do
|
||||||
|
let(:iso_env) { isolated_environment }
|
||||||
|
let(:boxes) { Vagrant::BoxCollection.new(iso_env.boxes_dir) }
|
||||||
|
|
||||||
|
it "should return a basic configured machine" do
|
||||||
|
provider_cls = register_provider("foo")
|
||||||
|
|
||||||
|
configure do |config|
|
||||||
|
config.vm.box = "foo"
|
||||||
|
end
|
||||||
|
|
||||||
|
results = subject.machine_config(:default, :foo, boxes)
|
||||||
|
box = results[:box]
|
||||||
|
config = results[:config]
|
||||||
|
expect(config.vm.box).to eq("foo")
|
||||||
|
expect(box).to be_nil
|
||||||
|
expect(results[:provider_cls]).to equal(provider_cls)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "configures with sub-machine config" do
|
||||||
|
register_provider("foo")
|
||||||
|
|
||||||
|
configure do |config|
|
||||||
|
config.ssh.port = "1"
|
||||||
|
config.vm.box = "base"
|
||||||
|
|
||||||
|
config.vm.define "foo" do |f|
|
||||||
|
f.ssh.port = 100
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
results = subject.machine_config(:foo, :foo, boxes)
|
||||||
|
config = results[:config]
|
||||||
|
expect(config.vm.box).to eq("base")
|
||||||
|
expect(config.ssh.port).to eq(100)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "configures with box configuration if it exists" do
|
||||||
|
register_provider("foo")
|
||||||
|
|
||||||
|
configure do |config|
|
||||||
|
config.vm.box = "base"
|
||||||
|
end
|
||||||
|
|
||||||
|
iso_env.box3("base", "1.0", :foo, vagrantfile: <<-VF)
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.ssh.port = 123
|
||||||
|
end
|
||||||
|
VF
|
||||||
|
|
||||||
|
results = subject.machine_config(:default, :foo, boxes)
|
||||||
|
box = results[:box]
|
||||||
|
config = results[:config]
|
||||||
|
expect(config.vm.box).to eq("base")
|
||||||
|
expect(config.ssh.port).to eq(123)
|
||||||
|
expect(box).to_not be_nil
|
||||||
|
expect(box.name).to eq("base")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "configures with the proper box version" do
|
||||||
|
register_provider("foo")
|
||||||
|
|
||||||
|
configure do |config|
|
||||||
|
config.vm.box = "base"
|
||||||
|
config.vm.box_version = "~> 1.2"
|
||||||
|
end
|
||||||
|
|
||||||
|
iso_env.box3("base", "1.0", :foo, vagrantfile: <<-VF)
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.ssh.port = 123
|
||||||
|
end
|
||||||
|
VF
|
||||||
|
|
||||||
|
iso_env.box3("base", "1.3", :foo, vagrantfile: <<-VF)
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.ssh.port = 245
|
||||||
|
end
|
||||||
|
VF
|
||||||
|
|
||||||
|
results = subject.machine_config(:default, :foo, boxes)
|
||||||
|
box = results[:box]
|
||||||
|
config = results[:config]
|
||||||
|
expect(config.vm.box).to eq("base")
|
||||||
|
expect(config.ssh.port).to eq(245)
|
||||||
|
expect(box).to_not be_nil
|
||||||
|
expect(box.name).to eq("base")
|
||||||
|
expect(box.version).to eq("1.3")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "configures with box config of other supported formats" do
|
||||||
|
register_provider("foo", nil, box_format: "bar")
|
||||||
|
|
||||||
|
configure do |config|
|
||||||
|
config.vm.box = "base"
|
||||||
|
end
|
||||||
|
|
||||||
|
iso_env.box3("base", "1.0", :bar, vagrantfile: <<-VF)
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.ssh.port = 123
|
||||||
|
end
|
||||||
|
VF
|
||||||
|
|
||||||
|
results = subject.machine_config(:default, :foo, boxes)
|
||||||
|
config = results[:config]
|
||||||
|
expect(config.vm.box).to eq("base")
|
||||||
|
expect(config.ssh.port).to eq(123)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "loads provider overrides if set" do
|
||||||
|
register_provider("foo")
|
||||||
|
register_provider("bar")
|
||||||
|
|
||||||
|
configure do |config|
|
||||||
|
config.ssh.port = 1
|
||||||
|
config.vm.box = "base"
|
||||||
|
|
||||||
|
config.vm.provider "foo" do |_, c|
|
||||||
|
c.ssh.port = 100
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Test with the override
|
||||||
|
results = subject.machine_config(:default, :foo, boxes)
|
||||||
|
config = results[:config]
|
||||||
|
expect(config.vm.box).to eq("base")
|
||||||
|
expect(config.ssh.port).to eq(100)
|
||||||
|
|
||||||
|
# Test without the override
|
||||||
|
results = subject.machine_config(:default, :bar, boxes)
|
||||||
|
config = results[:config]
|
||||||
|
expect(config.vm.box).to eq("base")
|
||||||
|
expect(config.ssh.port).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "loads the proper box if in a provider override" do
|
||||||
|
register_provider("foo")
|
||||||
|
|
||||||
|
configure do |config|
|
||||||
|
config.vm.box = "base"
|
||||||
|
|
||||||
|
config.vm.provider "foo" do |_, c|
|
||||||
|
c.vm.box = "foobox"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
iso_env.box3("base", "1.0", :foo, vagrantfile: <<-VF)
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.ssh.port = 123
|
||||||
|
end
|
||||||
|
VF
|
||||||
|
|
||||||
|
iso_env.box3("foobox", "1.0", :foo, vagrantfile: <<-VF)
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.ssh.port = 234
|
||||||
|
end
|
||||||
|
VF
|
||||||
|
|
||||||
|
results = subject.machine_config(:default, :foo, boxes)
|
||||||
|
config = results[:config]
|
||||||
|
box = results[:box]
|
||||||
|
expect(config.vm.box).to eq("foobox")
|
||||||
|
expect(config.ssh.port).to eq(234)
|
||||||
|
expect(box).to_not be_nil
|
||||||
|
expect(box.name).to eq("foobox")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises an error if the machine is not found" do
|
||||||
|
expect { subject.machine_config(:foo, :foo, boxes) }.
|
||||||
|
to raise_error(Vagrant::Errors::MachineNotFound)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises an error if the provider is not found" do
|
||||||
|
expect { subject.machine_config(:default, :foo, boxes) }.
|
||||||
|
to raise_error(Vagrant::Errors::ProviderNotFound)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#machine_names" do
|
||||||
|
it "returns the default name when single-VM" do
|
||||||
|
configure { |config| }
|
||||||
|
|
||||||
|
expect(subject.machine_names).to eq([:default])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns all of the names in a multi-VM" do
|
||||||
|
configure do |config|
|
||||||
|
config.vm.define "foo"
|
||||||
|
config.vm.define "bar"
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(subject.machine_names).to eq(
|
||||||
|
[:foo, :bar])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#primary_machine_name" do
|
||||||
|
it "returns the default name when single-VM" do
|
||||||
|
configure { |config| }
|
||||||
|
|
||||||
|
expect(subject.primary_machine_name).to eq(:default)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the designated machine in multi-VM" do
|
||||||
|
configure do |config|
|
||||||
|
config.vm.define "foo"
|
||||||
|
config.vm.define "bar", primary: true
|
||||||
|
config.vm.define "baz"
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(subject.primary_machine_name).to eq(:bar)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns nil if no designation in multi-VM" do
|
||||||
|
configure do |config|
|
||||||
|
config.vm.define "foo"
|
||||||
|
config.vm.define "baz"
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(subject.primary_machine_name).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue