core: add Vagrantfile class, tests
This commit is contained in:
parent
0f2fff2420
commit
99346cc516
|
@ -0,0 +1,157 @@
|
||||||
|
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
|
||||||
|
# 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 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
|
||||||
|
#
|
||||||
|
# @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.
|
||||||
|
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
|
||||||
|
|
||||||
|
box_formats = provider_plugin[1][: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
|
||||||
|
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)
|
||||||
|
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 config, config_warnings, 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
|
|
@ -0,0 +1,230 @@
|
||||||
|
require File.expand_path("../../base", __FILE__)
|
||||||
|
|
||||||
|
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) }
|
||||||
|
|
||||||
|
describe "#machine_config" do
|
||||||
|
let(:iso_env) { isolated_environment }
|
||||||
|
let(:boxes) { Vagrant::BoxCollection.new(iso_env.boxes_dir) }
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
it "should return a basic configured machine" do
|
||||||
|
register_provider("foo")
|
||||||
|
|
||||||
|
configure do |config|
|
||||||
|
config.vm.box = "foo"
|
||||||
|
end
|
||||||
|
|
||||||
|
config, _ = subject.machine_config(:default, :foo, boxes)
|
||||||
|
expect(config.vm.box).to eq("foo")
|
||||||
|
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
|
||||||
|
|
||||||
|
config, _ = subject.machine_config(:foo, :foo, boxes)
|
||||||
|
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.box2("base", :foo, vagrantfile: <<-VF)
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.ssh.port = 123
|
||||||
|
end
|
||||||
|
VF
|
||||||
|
|
||||||
|
config, _ = subject.machine_config(:default, :foo, boxes)
|
||||||
|
expect(config.vm.box).to eq("base")
|
||||||
|
expect(config.ssh.port).to eq(123)
|
||||||
|
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.box2("base", :bar, vagrantfile: <<-VF)
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.ssh.port = 123
|
||||||
|
end
|
||||||
|
VF
|
||||||
|
|
||||||
|
config, _ = subject.machine_config(:default, :foo, boxes)
|
||||||
|
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
|
||||||
|
config, _ = subject.machine_config(:default, :foo, boxes)
|
||||||
|
expect(config.vm.box).to eq("base")
|
||||||
|
expect(config.ssh.port).to eq(100)
|
||||||
|
|
||||||
|
# Test without the override
|
||||||
|
config, _ = subject.machine_config(:default, :bar, boxes)
|
||||||
|
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.box2("base", :foo, vagrantfile: <<-VF)
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.ssh.port = 123
|
||||||
|
end
|
||||||
|
VF
|
||||||
|
|
||||||
|
iso_env.box2("foobox", :foo, vagrantfile: <<-VF)
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.ssh.port = 234
|
||||||
|
end
|
||||||
|
VF
|
||||||
|
|
||||||
|
config, _ = subject.machine_config(:default, :foo, boxes)
|
||||||
|
expect(config.vm.box).to eq("foobox")
|
||||||
|
expect(config.ssh.port).to eq(234)
|
||||||
|
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
|
||||||
|
before do
|
||||||
|
keys << :test
|
||||||
|
end
|
||||||
|
|
||||||
|
def configure(&block)
|
||||||
|
loader.set(:test, [["2", block]])
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
before do
|
||||||
|
keys << :test
|
||||||
|
end
|
||||||
|
|
||||||
|
def configure(&block)
|
||||||
|
loader.set(:test, [["2", block]])
|
||||||
|
end
|
||||||
|
|
||||||
|
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