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" 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" require "vagrant/plugin/v2/errors"
module Vagrant 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 result
end 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. # This returns all the registered guests.
# #
# @return [Hash] # @return [Hash]
@ -113,6 +94,19 @@ module Vagrant
providers providers
end 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. # This returns all registered provisioners.
# #
# @return [Hash] # @return [Hash]

View File

@ -2,6 +2,8 @@ require "set"
require "log4r" require "log4r"
require "vagrant/plugin/v2/components"
module Vagrant module Vagrant
module Plugin module Plugin
module V2 module V2
@ -25,6 +27,13 @@ module Vagrant
@manager ||= Manager.new @manager ||= Manager.new
end 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 # 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 will be registered and available. Before this is called, a
# plugin does not exist. The name must be unique among all installed # 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. # without breaking anything in future versions of Vagrant.
# #
# @param [String] name Configuration key. # @param [String] name Configuration key.
# @param [Boolean] upgrade_safe If this is true, then this configuration # XXX: Document options hash
# key is safe to load during an upgrade, meaning that it depends def self.config(name=UNSET_VALUE, options=nil, &block)
# 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)
data[:config] ||= Registry.new data[:config] ||= Registry.new
# Register a new config class only if a name was given. # Register a new config class only if a name was given.
if name != UNSET_VALUE if name != UNSET_VALUE
data[:config].register(name.to_sym, &block) options ||= {}
# If we were told this is an upgrade safe configuration class if options[:provider]
# then we add it to the set. # This config is for a specific provider. Register it as
if upgrade_safe # a provider config component.
data[:config_upgrade_safe] ||= Set.new components.provider_configs.register(name.to_sym, &block)
data[:config_upgrade_safe].add(name.to_sym) else
# This is a generic configuration plugin, register it as such.
data[:config].register(name.to_sym, &block)
end end
end end

View File

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

View File

@ -1,16 +1,48 @@
require "log4r"
require "vagrant/util/stacked_proc_runner"
module VagrantPlugins module VagrantPlugins
module Kernel_V2 module Kernel_V2
# Represents a single configured provider for a VM. This may or may # 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 class VagrantConfigProvider
attr_reader :name attr_reader :name
attr_reader :config
# Initializes a new provider configuration for a VM. This should # Initializes a new provider configuration for a VM. This should
# only be instantiated internally by calling `config.vm.provider`. # only be instantiated internally by calling `config.vm.provider`.
# #
# @param [Symbol] name The name of the provider that is registered. # @param [Symbol] name The name of the provider that is registered.
def initialize(name) def initialize(name, block)
@name = name @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 end
end end

View File

@ -11,31 +11,31 @@ module VagrantPlugins
basic functionality of Vagrant version 2. basic functionality of Vagrant version 2.
DESC DESC
# Core configuration keys provided by the kernel. Note that all # Core configuration keys provided by the kernel. Note that unlike
# the kernel configuration classes are marked as _upgrade safe_ (the # "kernel_v1", none of these configuration classes are upgradable.
# true 2nd param). This means that these can be loaded in ANY version # This is by design, since we can't be sure if they're upgradable
# of the core of Vagrant. # until another version is available.
config("ssh", true) do config("ssh") do
require File.expand_path("../config/ssh", __FILE__) require File.expand_path("../config/ssh", __FILE__)
SSHConfig SSHConfig
end end
config("nfs", true) do config("nfs") do
require File.expand_path("../config/nfs", __FILE__) require File.expand_path("../config/nfs", __FILE__)
NFSConfig NFSConfig
end end
config("package", true) do config("package") do
require File.expand_path("../config/package", __FILE__) require File.expand_path("../config/package", __FILE__)
PackageConfig PackageConfig
end end
config("vagrant", true) do config("vagrant") do
require File.expand_path("../config/vagrant", __FILE__) require File.expand_path("../config/vagrant", __FILE__)
VagrantConfig VagrantConfig
end end
config("vm", true) do config("vm") do
require File.expand_path("../config/vm", __FILE__) require File.expand_path("../config/vm", __FILE__)
VMConfig VMConfig
end 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" instance.config[:bar].should == "baz"
end 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 it "should enumerate registered guest classes" do
pA = plugin do |p| pA = plugin do |p|
p.guest("foo") { "bar" } p.guest("foo") { "bar" }
@ -111,4 +95,22 @@ describe Vagrant::Plugin::V2::Manager do
instance.providers[:foo].should == "bar" instance.providers[:foo].should == "bar"
instance.providers[:bar].should == "baz" instance.providers[:bar].should == "baz"
end 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 end

View File

@ -126,6 +126,14 @@ describe Vagrant::Plugin::V2::Plugin do
plugin.config[:foo] plugin.config[:foo]
}.to raise_error(StandardError) }.to raise_error(StandardError)
end 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 end
describe "easy commands" do describe "easy commands" do