# File lib/vagrant/vagrantfile.rb, line 295 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
class Vagrant::Vagrantfile
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.
Attributes
This is the configuration loaded as-is given the loader and keys to initialize.
Public Class Methods
Initializes by loading a Vagrantfile
.
@param [Config::Loader] loader Configuration loader that should
already be configured with the proper Vagrantfile 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).
# File lib/vagrant/vagrantfile.rb, line 28 def initialize(loader, keys) @keys = keys @loader = loader @config, _ = loader.load(keys) @logger = Log4r::Logger.new("vagrant::vagrantfile") end
Public Instance Methods
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]
# File lib/vagrant/vagrantfile.rb, line 47 def machine(name, provider, boxes, data_path, env) # Load the configuration for the machine results = machine_config(name, provider, boxes, data_path) 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 machine data directory if it doesn't exist # XXX: Permissions error here. FileUtils.mkdir_p(data_path) # 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.
@param [Pathname] data_path Machine
data path @return [Hash<Symbol, Object>] Various configuration parameters for a
machine. See the main documentation body for more info.
# File lib/vagrant/vagrantfile.rb, line 116 def machine_config(name, provider, boxes, data_path=nil, validate_provider=true) keys = @keys.dup sub_machine = @config.vm.defined_vms[name] if !sub_machine raise Errors::MachineNotFound, name: name, provider: provider end provider_plugin = nil provider_cls = nil provider_options = {} box_formats = nil if provider != nil provider_plugin = Vagrant.plugin("2").manager.providers[provider] if !provider_plugin && validate_provider providers = Vagrant.plugin("2").manager.providers.to_hash.keys if providers providers_str = providers.join(', ') else providers_str = "N/A" end if providers.include? provider.downcase raise Errors::ProviderNotFoundSuggestion, machine: name, provider: provider, suggestion: provider.downcase, providers: providers_str end raise Errors::ProviderNotFound, machine: name, provider: provider, providers: providers_str end if validate_provider provider_cls = provider_plugin[0] provider_options = provider_plugin[1] box_formats = provider_options[:box_format] || provider # Test if the provider is usable or not begin provider_cls.usable?(true) rescue Errors::VagrantError => e raise Errors::ProviderNotUsable, machine: name.to_s, provider: provider.to_s, message: e.to_s end else box_formats = provider end end # 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 initial_box = original_box = config.vm.box initial_version = original_version = config.vm.box_version # Check if this machine has a local box metadata file # describing the existing guest. If so, load it and # set the box name and version to allow the actual # box in use to be discovered. if data_path meta_file = data_path.join("box_meta") if meta_file.file? box_meta = JSON.parse(meta_file.read) config.vm.box = box_meta["name"] config.vm.box_version = box_meta["version"] end end # 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.to_s.empty? && boxes box = boxes.find(config.vm.box, box_formats, config.vm.box_version) if box box_vagrantfile = find_vagrantfile(box.directory) if box_vagrantfile && !config.vm.ignore_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) elsif box_vagrantfile && config.vm.ignore_box_vagrantfile @logger.warn("Ignoring #{box.name} provided Vagrantfile inside box") 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 || original_version != config.vm.box_version # TODO: infinite loop protection? original_box = config.vm.box original_version = config.vm.box_version load_box_proc.call end end # Load the box and provider overrides load_box_proc.call # NOTE: In cases where the box_meta file contains stale information # and the reference box no longer exists, fall back to initial # configuration and attempt to load that if box.nil? @logger.warn("Failed to locate #{config.vm.box} with version #{config.vm.box_version}") @logger.warn("Performing lookup with initial values #{initial_box} with version #{initial_version}") config.vm.box = original_box = initial_box config.vm.box_version = original_box = initial_version load_box_proc.call end # Ensure box attributes are set to original values in # case they were modified by the local box metadata config.vm.box = original_box config.vm.box_version = original_version return { box: box, provider_cls: provider_cls, provider_options: provider_options.dup, 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>]
# File lib/vagrant/vagrantfile.rb, line 270 def machine_names @config.vm.defined_vm_keys.dup end
Returns a list of the machine names as well as the options that were specified for that machine.
@return [Hash<Symbol, Hash>]
# File lib/vagrant/vagrantfile.rb, line 278 def machine_names_and_options {}.tap do |r| @config.vm.defined_vms.each do |name, subvm| r[name] = subvm.options || {} end end 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]
Protected Instance Methods
# File lib/vagrant/vagrantfile.rb, line 310 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