Begin work on supporting provider-specific configuration

This works by registering a `config` with `:provider => true` with the
same name as your provider. Vagrant will then automatically configure
the provider when `config.vm.provider` is used.
This commit is contained in:
Mitchell Hashimoto 2012-11-19 07:55:30 +01:00
parent 666f9f802d
commit 1ee470a551
10 changed files with 132 additions and 63 deletions

View File

@ -1,5 +1,8 @@
require "log4r"
# We don't autoload components because if we're loading anything in the
# V2 namespace anyways, then we're going to need the Components class.
require "vagrant/plugin/v2/components"
require "vagrant/plugin/v2/errors"
module Vagrant

View File

@ -0,0 +1,14 @@
module Vagrant
module Plugin
module V2
# This is the container class for the components of a single plugin.
class Components
attr_reader :provider_configs
def initialize
@provider_configs = Registry.new
end
end
end
end
end

View File

@ -55,25 +55,6 @@ module Vagrant
result
end
# This returns all the registered configuration classes that were
# marked as "upgrade safe."
#
# @return [Hash]
def config_upgrade_safe
result = {}
@registered.each do |plugin|
configs = plugin.data[:config_upgrade_safe]
if configs
configs.each do |key|
result[key] = plugin.config.get(key)
end
end
end
result
end
# This returns all the registered guests.
#
# @return [Hash]
@ -113,6 +94,19 @@ module Vagrant
providers
end
# This returns all the config classes for the various providers.
#
# @return [Hash]
def provider_configs
configs = {}
@registered.each do |plugin|
configs.merge!(plugin.components.provider_configs.to_hash)
end
configs
end
# This returns all registered provisioners.
#
# @return [Hash]

View File

@ -2,6 +2,8 @@ require "set"
require "log4r"
require "vagrant/plugin/v2/components"
module Vagrant
module Plugin
module V2
@ -25,6 +27,13 @@ module Vagrant
@manager ||= Manager.new
end
# Returns the {Components} for this plugin.
#
# @return [Components]
def self.components
@components ||= Components.new
end
# Set the name of the plugin. The moment that this is called, the
# plugin will be registered and available. Before this is called, a
# plugin does not exist. The name must be unique among all installed
@ -118,24 +127,21 @@ module Vagrant
# without breaking anything in future versions of Vagrant.
#
# @param [String] name Configuration key.
# @param [Boolean] upgrade_safe If this is true, then this configuration
# key is safe to load during an upgrade, meaning that it depends
# on NO Vagrant internal classes. Do _not_ set this to true unless
# you really know what you're doing, since you can cause Vagrant
# to crash (although Vagrant will output a user-friendly error
# message if this were to happen).
def self.config(name=UNSET_VALUE, upgrade_safe=false, &block)
# XXX: Document options hash
def self.config(name=UNSET_VALUE, options=nil, &block)
data[:config] ||= Registry.new
# Register a new config class only if a name was given.
if name != UNSET_VALUE
data[:config].register(name.to_sym, &block)
options ||= {}
# If we were told this is an upgrade safe configuration class
# then we add it to the set.
if upgrade_safe
data[:config_upgrade_safe] ||= Set.new
data[:config_upgrade_safe].add(name.to_sym)
if options[:provider]
# This config is for a specific provider. Register it as
# a provider config component.
components.provider_configs.register(name.to_sym, &block)
else
# This is a generic configuration plugin, register it as such.
data[:config].register(name.to_sym, &block)
end
end

View File

@ -29,7 +29,7 @@ module VagrantPlugins
@forwarded_ports = []
@shared_folders = {}
@networks = []
@providers = []
@providers = {}
@provisioners = []
@customizations = []
end
@ -76,8 +76,9 @@ module VagrantPlugins
# Configures a provider for this VM.
#
# @param [Symbol] name The name of the provider.
def provider(name)
@providers << VagrantConfigProvider.new(name)
def provider(name, &block)
# TODO: Error if a provider is defined multiple times.
@providers[name] = VagrantConfigProvider.new(name, block)
end
def provision(name, options=nil, &block)

View File

@ -1,16 +1,48 @@
require "log4r"
require "vagrant/util/stacked_proc_runner"
module VagrantPlugins
module Kernel_V2
# Represents a single configured provider for a VM. This may or may
# not be a valid provider.
# not be a valid provider. Validation is deferred until later.
class VagrantConfigProvider
attr_reader :name
attr_reader :config
# Initializes a new provider configuration for a VM. This should
# only be instantiated internally by calling `config.vm.provider`.
#
# @param [Symbol] name The name of the provider that is registered.
def initialize(name)
@name = name
def initialize(name, block)
@name = name
@config = nil
@logger = Log4r::Logger.new("vagrant::config::vm::provider")
# If we were given a block to configure with, then let's try
# to do that.
load_config(block) if block
end
protected
# This takes the config block given to define the provider and
# attempts to turn this into a real configuration object. If the
# provider plugin is not found then it is simply ignored. This allows
# people to share Vagrantfiles that have configuration for providers
# which may not be setup on every user's system.
#
# @param [Proc] config_proc
def load_config(config_proc)
config_class = Vagrant.plugin("2").manager.provider_configs[@name]
if !config_class
@logger.info("Provider config for #{@name} not found, ignoring that config.")
return
end
@logger.info("Configuring provider #{@name} with #{config_class}")
@config = config_class.new
config_proc.call(@config)
end
end
end

View File

@ -11,31 +11,31 @@ module VagrantPlugins
basic functionality of Vagrant version 2.
DESC
# Core configuration keys provided by the kernel. Note that all
# the kernel configuration classes are marked as _upgrade safe_ (the
# true 2nd param). This means that these can be loaded in ANY version
# of the core of Vagrant.
config("ssh", true) do
# Core configuration keys provided by the kernel. Note that unlike
# "kernel_v1", none of these configuration classes are upgradable.
# This is by design, since we can't be sure if they're upgradable
# until another version is available.
config("ssh") do
require File.expand_path("../config/ssh", __FILE__)
SSHConfig
end
config("nfs", true) do
config("nfs") do
require File.expand_path("../config/nfs", __FILE__)
NFSConfig
end
config("package", true) do
config("package") do
require File.expand_path("../config/package", __FILE__)
PackageConfig
end
config("vagrant", true) do
config("vagrant") do
require File.expand_path("../config/vagrant", __FILE__)
VagrantConfig
end
config("vm", true) do
config("vm") do
require File.expand_path("../config/vm", __FILE__)
VMConfig
end

View File

@ -0,0 +1,9 @@
require File.expand_path("../../../../base", __FILE__)
describe Vagrant::Plugin::V2::Components do
let(:instance) { described_class.new }
it "should have provider configs" do
instance.provider_configs.should be_kind_of(Vagrant::Registry)
end
end

View File

@ -45,22 +45,6 @@ describe Vagrant::Plugin::V2::Manager do
instance.config[:bar].should == "baz"
end
it "should enumerate registered upgrade safe config classes" do
pA = plugin do |p|
p.config("foo", true) { "bar" }
end
pB = plugin do |p|
p.config("bar") { "baz" }
end
instance.register(pA)
instance.register(pB)
instance.config_upgrade_safe.length.should == 1
instance.config_upgrade_safe[:foo].should == "bar"
end
it "should enumerate registered guest classes" do
pA = plugin do |p|
p.guest("foo") { "bar" }
@ -111,4 +95,22 @@ describe Vagrant::Plugin::V2::Manager do
instance.providers[:foo].should == "bar"
instance.providers[:bar].should == "baz"
end
it "provides the collection of registered provider configs" do
pA = plugin do |p|
p.config("foo", :provider => true) { "foo" }
end
pB = plugin do |p|
p.config("bar", :provider => true) { "bar" }
p.config("baz") { "baz" }
end
instance.register(pA)
instance.register(pB)
instance.provider_configs.length.should == 2
instance.provider_configs[:foo].should == "foo"
instance.provider_configs[:bar].should == "bar"
end
end

View File

@ -126,6 +126,14 @@ describe Vagrant::Plugin::V2::Plugin do
plugin.config[:foo]
}.to raise_error(StandardError)
end
it "should register configuration classes for providers" do
plugin = Class.new(described_class) do
config("foo", :provider => true) { "bar" }
end
plugin.components.provider_configs[:foo].should == "bar"
end
end
describe "easy commands" do