VM-specific configuration now works.

This commit is contained in:
Mitchell Hashimoto 2011-12-03 19:05:50 -08:00
parent 73a672cff1
commit 99982fb26e
12 changed files with 166 additions and 26 deletions

View File

@ -38,6 +38,10 @@ module Vagrant
# Make all sources an array.
data = [data] if !data.kind_of?(Array)
# Clear the cache for this key only if the data is different
@proc_cache.delete(name) if @sources[name] && @sources[name] != data
@sources[name] = data
end

View File

@ -71,10 +71,6 @@ module Vagrant
push_proc(&block)
end
def has_multi_vms?
!defined_vms.empty?
end
def defined_vms
@defined_vms ||= {}
end

View File

@ -9,7 +9,7 @@ module Vagrant
# access to the VMs, CLI, etc. all in the scope of this environment.
class Environment
HOME_SUBDIRS = ["tmp", "boxes", "logs"]
DEFAULT_VM = :default
DEFAULT_VM = "default"
DEFAULT_HOME = "~/.vagrant.d"
# Parent environment (in the case of multi-VMs)
@ -439,13 +439,27 @@ module Vagrant
# to load the configuration in two-passes. We do this because the
# first pass is used to determine the box for the VM. The second pass
# is used to also load the box Vagrantfile.
vm_configs = global.vm.defined_vm_keys.map do |vm_name|
defined_vm_keys = global.vm.defined_vm_keys.dup
defined_vms = global.vm.defined_vms.dup
# If this isn't a multi-VM environment, then setup the default VM
# to simply be our configuration.
if defined_vm_keys.empty?
defined_vm_keys << DEFAULT_VM
defined_vms[DEFAULT_VM] = Config::VMConfig::SubVM.new
end
vm_configs = defined_vm_keys.map do |vm_name|
@logger.debug("Loading configuration for VM: #{vm_name}")
subvm = defined_vms[vm_name]
# First pass, first run.
config = inner_load[vm_name]
config = inner_load[subvm]
# Second pass, with the box
config = inner_load[global.vm.defined_vms[vm_name], config.vm.box]
config.vm.name = vm_name
config = inner_load[subvm, config.vm.box]
config.vm.name = vm_name.to_s
# Return the final configuration for this VM
config

View File

@ -6,6 +6,7 @@ require "log4r"
# Add this directory to the load path, since it just makes
# everything else so much easier.
$:.unshift File.expand_path("../", __FILE__)
$:.unshift File.expand_path("../../", __FILE__)
# Load in the supporting files for our tests
require "support/shared/base_context"

View File

@ -4,8 +4,8 @@ require "pathname"
require "log4r"
require "childprocess"
require File.expand_path("../tempdir", __FILE__)
require File.expand_path("../virtualbox", __FILE__)
require "support/tempdir"
require "support/virtualbox"
module Acceptance
# This class manages an isolated environment for Vagrant to

View File

@ -8,6 +8,7 @@ require "vagrant"
# Add this directory to the load path, since it just makes
# everything else easier.
$:.unshift File.expand_path("../", __FILE__)
$:.unshift File.expand_path("../../", __FILE__)
# Load in helpers
require "support/shared/base_context"

View File

@ -0,0 +1,52 @@
require "fileutils"
require "pathname"
require "log4r"
require "support/tempdir"
module Unit
# This class manages an isolated environment for Vagrant to
# run in. It creates a temporary directory to act as the
# working directory as well as sets a custom home directory.
#
# This class also provides various helpers to create Vagrantfiles,
# boxes, etc.
class IsolatedEnvironment
attr_reader :homedir
attr_reader :workdir
# Initializes an isolated environment. You can pass in some
# options here to configure runing custom applications in place
# of others as well as specifying environmental variables.
#
# @param [Hash] apps A mapping of application name (such as "vagrant")
# to an alternate full path to the binary to run.
# @param [Hash] env Additional environmental variables to inject
# into the execution environments.
def initialize(apps=nil, env=nil)
@logger = Log4r::Logger.new("unit::isolated_environment")
# Create a temporary directory for our work
@tempdir = Tempdir.new("vagrant")
@logger.info("Initialize isolated environment: #{@tempdir.path}")
# Setup the home and working directories
@homedir = Pathname.new(File.join(@tempdir.path, "home"))
@workdir = Pathname.new(File.join(@tempdir.path, "work"))
@homedir.mkdir
@workdir.mkdir
end
def create_vagrant_env
Vagrant::Environment.new(:cwd => @workdir, :home_path => @homedir)
end
def vagrantfile(contents)
@workdir.join("Vagrantfile").open("w+") do |f|
f.write(contents)
end
end
end
end

View File

@ -1,6 +1,20 @@
require "tempfile"
require "support/isolated_environment"
shared_context "unit" do
# This creates an isolated environment so that Vagrant doesn't
# muck around with your real system during unit tests.
#
# The returned isolated environment has a variety of helper
# methods on it to easily create files, Vagrantfiles, boxes,
# etc.
def isolated_environment
env = Unit::IsolatedEnvironment.new
yield env if block_given?
env
end
# This helper creates a temporary file and returns a Pathname
# object pointed to it.
def temporary_file(contents=nil)

View File

@ -32,6 +32,34 @@ describe Vagrant::Config::Loader do
$_config_data.should == 1
end
it "should clear cache on setting to a new value" do
$_config_data = 0
instance.load_order = [:proc]
instance.set(:proc, temporary_file("$_config_data += 1"))
5.times { instance.load }
instance.set(:proc, temporary_file("$_config_data += 1"))
5.times { instance.load }
$_config_data.should == 2
end
it "should not clear the cache if setting to the same value multiple times" do
$_config_data = 0
file = temporary_file("$_config_data += 1")
instance.load_order = [:proc]
instance.set(:proc, file)
5.times { instance.load }
instance.set(:proc, file)
5.times { instance.load }
$_config_data.should == 1
end
it "should raise proper error if there is a syntax error in a Vagrantfile" do
instance.load_order = [:file]
instance.set(:file, temporary_file("Vagrant:^Config"))

View File

@ -2,7 +2,11 @@ require File.expand_path("../../base", __FILE__)
require "pathname"
require "support/tempdir"
describe Vagrant::Environment do
include_context "unit"
describe "current working directory" do
it "is the cwd by default" do
described_class.new.cwd.should == Pathname.new(Dir.pwd)
@ -16,8 +20,9 @@ describe Vagrant::Environment do
describe "home path" do
it "is set to the home path given" do
instance = described_class.new(:home_path => "/tmp/foo")
instance.home_path.should == Pathname.new("/tmp/foo")
dir = Tempdir.new.path
instance = described_class.new(:home_path => dir)
instance.home_path.should == Pathname.new(dir)
end
it "is set to the environmental variable VAGRANT_HOME" do
@ -31,19 +36,53 @@ describe Vagrant::Environment do
end
describe "loading configuration" do
let(:home_path) { Pathname.new("/tmp/foo") }
let(:home_path) { Pathname.new(Tempdir.new.path) }
let(:instance) { described_class.new(:home_path => home_path) }
it "should load global configuration" do
File.open(home_path.join("Vagrantfile"), "w+") do |f|
f.write(<<-VF)
environment = isolated_environment do |env|
env.vagrantfile(<<-VF)
Vagrant::Config.run do |config|
config.vagrant.dotfile_name = "foo"
end
VF
end
instance.config.global.vagrant.dotfile_name.should == "foo"
env = environment.create_vagrant_env
env.config.global.vagrant.dotfile_name.should == "foo"
end
it "should load VM configuration" do
environment = isolated_environment do |env|
env.vagrantfile(<<-VF)
Vagrant::Config.run do |config|
config.vagrant.dotfile_name = "foo"
end
VF
end
env = environment.create_vagrant_env
env.config.for_vm("default").vm.name.should == "default"
end
it "should load VM configuration with multiple VMs" do
environment = isolated_environment do |env|
env.vagrantfile(<<-VF)
Vagrant::Config.run do |config|
config.vm.define :foo do |vm|
vm.ssh.port = 100
end
config.vm.define :bar do |vm|
vm.ssh.port = 200
end
end
VF
end
env = environment.create_vagrant_env
env.config.for_vm("foo").ssh.port.should == 100
env.config.for_vm("bar").ssh.port.should == 200
end
end

View File

@ -24,15 +24,6 @@ class ConfigVMTest < Test::Unit::TestCase
assert @config.defined_vms[:name].options[:set]
end
should "not have multi-VMs by default" do
assert !@config.has_multi_vms?
end
should "have multi-VMs once one is specified" do
@config.define(:foo) {}
assert @config.has_multi_vms?
end
should "retain vm definition order" do
@config.define(:a) {}
@config.define(:b) {}