Merge branch 'provisioner-revamp'
New provisioner API! Provisioners now have two methods to implement: * configure(root_config) - Allows provisioners to define new shared folders and such. * provision - The actual meat where the provisioner does things with the machine. Note that this removes a feature: `config.vm.provision` argument can no longer be a class object. It _must_ be a symbol (like ":chef"). Custom provisioners _must_ be created through the new plugin interface. This can all still be embedded in a single Vagrantfile.
This commit is contained in:
commit
9bdd9ed5bd
|
@ -18,11 +18,14 @@ module Vagrant
|
||||||
def call(env)
|
def call(env)
|
||||||
# Get all the configured provisioners
|
# Get all the configured provisioners
|
||||||
provisioners = env[:machine].config.vm.provisioners.map do |provisioner|
|
provisioners = env[:machine].config.vm.provisioners.map do |provisioner|
|
||||||
provisioner.provisioner.new(env, provisioner.config)
|
klass = Vagrant.plugin("2").manager.provisioners[provisioner.name]
|
||||||
|
klass.new(env[:machine], provisioner.config)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Instantiate and prepare them.
|
# Ask the provisioners to modify the configuration if needed
|
||||||
provisioners.map { |p| p.prepare }
|
provisioners.each do |p|
|
||||||
|
p.configure(env[:machine].config)
|
||||||
|
end
|
||||||
|
|
||||||
# Continue, we need the VM to be booted.
|
# Continue, we need the VM to be booted.
|
||||||
@app.call(env)
|
@app.call(env)
|
||||||
|
@ -32,7 +35,7 @@ module Vagrant
|
||||||
env[:ui].info(I18n.t("vagrant.actions.vm.provision.beginning",
|
env[:ui].info(I18n.t("vagrant.actions.vm.provision.beginning",
|
||||||
:provisioner => p.class))
|
:provisioner => p.class))
|
||||||
|
|
||||||
p.provision!
|
p.provision
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -329,7 +329,7 @@ module Vagrant
|
||||||
# will return nil, and we don't want to trigger a detect load.
|
# will return nil, and we don't want to trigger a detect load.
|
||||||
host_klass = config_global.vagrant.host
|
host_klass = config_global.vagrant.host
|
||||||
if host_klass.nil? || host_klass == :detect
|
if host_klass.nil? || host_klass == :detect
|
||||||
hosts = Vagrant.plugin("2").manager.hosts
|
hosts = Vagrant.plugin("2").manager.hosts.to_hash
|
||||||
|
|
||||||
# Get the flattened list of available hosts
|
# Get the flattened list of available hosts
|
||||||
host_klass = Hosts.detect(hosts)
|
host_klass = Hosts.detect(hosts)
|
||||||
|
|
|
@ -2,11 +2,18 @@ module Vagrant
|
||||||
module Plugin
|
module Plugin
|
||||||
module V2
|
module V2
|
||||||
# This is the container class for the components of a single plugin.
|
# This is the container class for the components of a single plugin.
|
||||||
|
# This allows us to separate the plugin class which defines the
|
||||||
|
# components, and the actual container of those components. This
|
||||||
|
# removes a bit of state overhead from the plugin class itself.
|
||||||
class Components
|
class Components
|
||||||
attr_reader :provider_configs
|
# This contains all the configuration plugins by scope.
|
||||||
|
#
|
||||||
|
# @return [Hash<Symbol, Registry>]
|
||||||
|
attr_reader :configs
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@provider_configs = Registry.new
|
# Create the configs hash which defaults to a registry
|
||||||
|
@configs = Hash.new { |h, k| h[k] = Registry.new }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,106 +18,99 @@ module Vagrant
|
||||||
#
|
#
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def commands
|
def commands
|
||||||
result = {}
|
Registry.new.tap do |result|
|
||||||
|
@registered.each do |plugin|
|
||||||
@registered.each do |plugin|
|
result.merge!(plugin.command)
|
||||||
result.merge!(plugin.command.to_hash)
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
result
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# This returns all the registered communicators.
|
# This returns all the registered communicators.
|
||||||
#
|
#
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def communicators
|
def communicators
|
||||||
result = {}
|
Registry.new.tap do |result|
|
||||||
|
@registered.each do |plugin|
|
||||||
@registered.each do |plugin|
|
result.merge!(plugin.communicator)
|
||||||
result.merge!(plugin.communicator.to_hash)
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
result
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# This returns all the registered configuration classes.
|
# This returns all the registered configuration classes.
|
||||||
#
|
#
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def config
|
def config
|
||||||
result = {}
|
Registry.new.tap do |result|
|
||||||
|
@registered.each do |plugin|
|
||||||
@registered.each do |plugin|
|
result.merge!(plugin.components.configs[:top])
|
||||||
plugin.config.each do |key, klass|
|
|
||||||
result[key] = klass
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
result
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# This returns all the registered guests.
|
# This returns all the registered guests.
|
||||||
#
|
#
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def guests
|
def guests
|
||||||
result = {}
|
Registry.new.tap do |result|
|
||||||
|
@registered.each do |plugin|
|
||||||
@registered.each do |plugin|
|
result.merge!(plugin.guest)
|
||||||
result.merge!(plugin.guest.to_hash)
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
result
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# This returns all registered host classes.
|
# This returns all registered host classes.
|
||||||
#
|
#
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def hosts
|
def hosts
|
||||||
hosts = {}
|
Registry.new.tap do |result|
|
||||||
|
@registered.each do |plugin|
|
||||||
@registered.each do |plugin|
|
result.merge!(plugin.host)
|
||||||
hosts.merge!(plugin.host.to_hash)
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
hosts
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# This returns all registered providers.
|
# This returns all registered providers.
|
||||||
#
|
#
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def providers
|
def providers
|
||||||
providers = {}
|
Registry.new.tap do |result|
|
||||||
|
@registered.each do |plugin|
|
||||||
@registered.each do |plugin|
|
result.merge!(plugin.provider)
|
||||||
providers.merge!(plugin.provider.to_hash)
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
providers
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# This returns all the config classes for the various providers.
|
# This returns all the config classes for the various providers.
|
||||||
#
|
#
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def provider_configs
|
def provider_configs
|
||||||
configs = {}
|
Registry.new.tap do |result|
|
||||||
|
@registered.each do |plugin|
|
||||||
@registered.each do |plugin|
|
result.merge!(plugin.components.configs[:provider])
|
||||||
configs.merge!(plugin.components.provider_configs.to_hash)
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
configs
|
# This returns all the config classes for the various provisioners.
|
||||||
|
#
|
||||||
|
# @return [Registry]
|
||||||
|
def provisioner_configs
|
||||||
|
Registry.new.tap do |result|
|
||||||
|
@registered.each do |plugin|
|
||||||
|
result.merge!(plugin.components.configs[:provisioner])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# This returns all registered provisioners.
|
# This returns all registered provisioners.
|
||||||
#
|
#
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def provisioners
|
def provisioners
|
||||||
results = {}
|
Registry.new.tap do |result|
|
||||||
|
@registered.each do |plugin|
|
||||||
@registered.each do |plugin|
|
result.merge!(plugin.provisioner)
|
||||||
results.merge!(plugin.provisioner.to_hash)
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
results
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# This registers a plugin. This should _NEVER_ be called by the public
|
# This registers a plugin. This should _NEVER_ be called by the public
|
||||||
|
|
|
@ -128,25 +128,10 @@ module Vagrant
|
||||||
#
|
#
|
||||||
# @param [String] name Configuration key.
|
# @param [String] name Configuration key.
|
||||||
# XXX: Document options hash
|
# XXX: Document options hash
|
||||||
def self.config(name=UNSET_VALUE, options=nil, &block)
|
def self.config(name, scope=nil, &block)
|
||||||
data[:config] ||= Registry.new
|
scope ||= :top
|
||||||
|
components.configs[scope].register(name.to_sym, &block)
|
||||||
# Register a new config class only if a name was given.
|
nil
|
||||||
if name != UNSET_VALUE
|
|
||||||
options ||= {}
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
# Return the registry
|
|
||||||
data[:config]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Defines an "easy hook," which gives an easier interface to hook
|
# Defines an "easy hook," which gives an easier interface to hook
|
||||||
|
|
|
@ -4,45 +4,42 @@ module Vagrant
|
||||||
# This is the base class for a provisioner for the V2 API. A provisioner
|
# This is the base class for a provisioner for the V2 API. A provisioner
|
||||||
# is primarily responsible for installing software on a Vagrant guest.
|
# is primarily responsible for installing software on a Vagrant guest.
|
||||||
class Provisioner
|
class Provisioner
|
||||||
# The environment which provisioner is running in. This is the
|
attr_reader :machine
|
||||||
# action environment, not a Vagrant::Environment.
|
|
||||||
attr_reader :env
|
|
||||||
|
|
||||||
# The configuration for this provisioner. This will be an instance of
|
|
||||||
# the `Config` class which is part of the provisioner.
|
|
||||||
attr_reader :config
|
attr_reader :config
|
||||||
|
|
||||||
def initialize(env, config)
|
# Initializes the provisioner with the machine that it will be
|
||||||
@env = env
|
# provisioning along with the provisioner configuration (if there
|
||||||
@config = config
|
# is any).
|
||||||
end
|
|
||||||
|
|
||||||
# This method is expected to return a class that is used for
|
|
||||||
# configuring the provisioner. This return value is expected to be
|
|
||||||
# a subclass of {Config}.
|
|
||||||
#
|
#
|
||||||
# @return [Config]
|
# The provisioner should _not_ do anything at this point except
|
||||||
def self.config_class
|
# initialize internal state.
|
||||||
|
#
|
||||||
|
# @param [Machine] machine The machine that this will be provisioning.
|
||||||
|
# @param [Object] config Provisioner configuration, if one was set.
|
||||||
|
def initialize(machine, config)
|
||||||
|
@machine = machine
|
||||||
|
@config = config
|
||||||
end
|
end
|
||||||
|
|
||||||
# This is the method called to "prepare" the provisioner. This is called
|
# Called with the root configuration of the machine so the provisioner
|
||||||
# before any actions are run by the action runner (see {Vagrant::Actions::Runner}).
|
# can add some configuration on top of the machine.
|
||||||
# This can be used to setup shared folders, forward ports, etc. Whatever is
|
#
|
||||||
# necessary on a "meta" level.
|
# During this step, and this step only, the provisioner should modify
|
||||||
|
# the root machine configuration to add any additional features it
|
||||||
|
# may need. Examples include sharing folders, networking, and so on.
|
||||||
|
# This step is guaranteed to be called before any of those steps are
|
||||||
|
# done so the provisioner may do that.
|
||||||
#
|
#
|
||||||
# No return value is expected.
|
# No return value is expected.
|
||||||
def prepare
|
def configure(root_config)
|
||||||
end
|
end
|
||||||
|
|
||||||
# This is the method called to provision the system. This method
|
# This is the method called when the actual provisioning should be
|
||||||
# is expected to do whatever necessary to provision the system (create files,
|
# done. The communicator is guaranteed to be ready at this point,
|
||||||
# SSH, etc.)
|
# and any shared folders or networks are already setup.
|
||||||
def provision!
|
#
|
||||||
end
|
# No return value is expected.
|
||||||
|
def provision
|
||||||
# This is the method called to when the system is being destroyed
|
|
||||||
# and allows the provisioners to engage in any cleanup tasks necessary.
|
|
||||||
def cleanup
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,6 +42,22 @@ module Vagrant
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Merge one registry with another and return a completely new
|
||||||
|
# registry. Note that the result cache is completely busted, so
|
||||||
|
# any gets on the new registry will result in a cache miss.
|
||||||
|
def merge(other)
|
||||||
|
self.class.new.tap do |result|
|
||||||
|
result.merge!(self)
|
||||||
|
result.merge!(other)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Like #{merge} but merges into self.
|
||||||
|
def merge!(other)
|
||||||
|
@items.merge!(other.__internal_state[:items])
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
# Converts this registry to a hash
|
# Converts this registry to a hash
|
||||||
def to_hash
|
def to_hash
|
||||||
result = {}
|
result = {}
|
||||||
|
@ -51,5 +67,12 @@ module Vagrant
|
||||||
|
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def __internal_state
|
||||||
|
{
|
||||||
|
:items => @items,
|
||||||
|
:results_cache => @results_cache
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -142,11 +142,6 @@ module VagrantPlugins
|
||||||
:name => name))
|
:name => name))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Each provisioner can validate itself
|
|
||||||
provisioners.each do |prov|
|
|
||||||
prov.validate(env, errors)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,51 +4,36 @@ module VagrantPlugins
|
||||||
module Kernel_V2
|
module Kernel_V2
|
||||||
# Represents a single configured provisioner for a VM.
|
# Represents a single configured provisioner for a VM.
|
||||||
class VagrantConfigProvisioner
|
class VagrantConfigProvisioner
|
||||||
attr_reader :shortcut
|
# The name of the provisioner that should be registered
|
||||||
attr_reader :provisioner
|
# as a plugin.
|
||||||
|
#
|
||||||
|
# @return [Symbol]
|
||||||
|
attr_reader :name
|
||||||
|
|
||||||
|
# The configuration associated with the provisioner, if there is any.
|
||||||
|
#
|
||||||
|
# @return [Object]
|
||||||
attr_reader :config
|
attr_reader :config
|
||||||
|
|
||||||
def initialize(shortcut, options=nil, &block)
|
def initialize(name, options=nil, &block)
|
||||||
@logger = Log4r::Logger.new("vagrant::config::vm::provisioner")
|
@logger = Log4r::Logger.new("vagrant::config::vm::provisioner")
|
||||||
@logger.debug("Provisioner config: #{shortcut}")
|
@logger.debug("Provisioner defined: #{name}")
|
||||||
@shortcut = shortcut
|
|
||||||
@provisioner = shortcut
|
|
||||||
@config = nil
|
@config = nil
|
||||||
|
@name = name
|
||||||
|
|
||||||
# If the shorcut is a symbol, we look through the registered
|
# Attempt to find the configuration class for this provider
|
||||||
# plugins to see if any define a provisioner we want.
|
# if it exists and load the configuration.
|
||||||
if shortcut.is_a?(Symbol)
|
config_class = Vagrant.plugin("2").manager.provisioner_configs[@name]
|
||||||
@provisioner = Vagrant.plugin("2").manager.provisioners[shortcut]
|
if !config_class
|
||||||
end
|
@logger.info("Provisioner config for '#{@name}' not found. Ignoring config.")
|
||||||
|
|
||||||
@logger.info("Provisioner class: #{provisioner}")
|
|
||||||
configure(options, &block) if @provisioner
|
|
||||||
end
|
|
||||||
|
|
||||||
# Configures the provisioner if it can (if it is valid).
|
|
||||||
def configure(options=nil, &block)
|
|
||||||
config_class = @provisioner.config_class
|
|
||||||
return if !config_class
|
|
||||||
|
|
||||||
@logger.debug("Configuring provisioner with: #{config_class}")
|
|
||||||
@config = config_class.new
|
|
||||||
@config.set_options(options) if options
|
|
||||||
block.call(@config) if block
|
|
||||||
end
|
|
||||||
|
|
||||||
def validate(env, errors)
|
|
||||||
if !provisioner
|
|
||||||
# If we don't have a provisioner then the whole thing is invalid.
|
|
||||||
errors.add(I18n.t("vagrant.config.vm.provisioner_not_found", :shortcut => shortcut))
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if !(provisioner <= Vagrant.plugin("2", :provisioner))
|
@config = config_class.new
|
||||||
errors.add(I18n.t("vagrant.config.vm.provisioner_invalid_class", :shortcut => shortcut))
|
@config.set_options(options) if options
|
||||||
end
|
block.call(@config) if block
|
||||||
|
@config.finalize!
|
||||||
# Pass on validation to the provisioner config
|
|
||||||
config.validate(env, errors) if config
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -37,7 +37,6 @@ module VagrantPlugins
|
||||||
autoload :NFS, File.expand_path("../action/nfs", __FILE__)
|
autoload :NFS, File.expand_path("../action/nfs", __FILE__)
|
||||||
autoload :Package, File.expand_path("../action/package", __FILE__)
|
autoload :Package, File.expand_path("../action/package", __FILE__)
|
||||||
autoload :PackageVagrantfile, File.expand_path("../action/package_vagrantfile", __FILE__)
|
autoload :PackageVagrantfile, File.expand_path("../action/package_vagrantfile", __FILE__)
|
||||||
autoload :ProvisionerCleanup, File.expand_path("../action/provisioner_cleanup", __FILE__)
|
|
||||||
autoload :PruneNFSExports, File.expand_path("../action/prune_nfs_exports", __FILE__)
|
autoload :PruneNFSExports, File.expand_path("../action/prune_nfs_exports", __FILE__)
|
||||||
autoload :Resume, File.expand_path("../action/resume", __FILE__)
|
autoload :Resume, File.expand_path("../action/resume", __FILE__)
|
||||||
autoload :SaneDefaults, File.expand_path("../action/sane_defaults", __FILE__)
|
autoload :SaneDefaults, File.expand_path("../action/sane_defaults", __FILE__)
|
||||||
|
@ -57,8 +56,8 @@ module VagrantPlugins
|
||||||
b.use CleanMachineFolder
|
b.use CleanMachineFolder
|
||||||
b.use ClearForwardedPorts
|
b.use ClearForwardedPorts
|
||||||
b.use EnvSet, :port_collision_handler => :correct
|
b.use EnvSet, :port_collision_handler => :correct
|
||||||
b.use CheckPortCollisions
|
|
||||||
b.use Provision
|
b.use Provision
|
||||||
|
b.use CheckPortCollisions
|
||||||
b.use PruneNFSExports
|
b.use PruneNFSExports
|
||||||
b.use NFS
|
b.use NFS
|
||||||
b.use ClearSharedFolders
|
b.use ClearSharedFolders
|
||||||
|
@ -90,7 +89,6 @@ module VagrantPlugins
|
||||||
b3.use CheckAccessible
|
b3.use CheckAccessible
|
||||||
b3.use EnvSet, :force => true
|
b3.use EnvSet, :force => true
|
||||||
b3.use action_halt
|
b3.use action_halt
|
||||||
b3.use ProvisionerCleanup
|
|
||||||
b3.use PruneNFSExports
|
b3.use PruneNFSExports
|
||||||
b3.use Destroy
|
b3.use Destroy
|
||||||
b3.use CleanMachineFolder
|
b3.use CleanMachineFolder
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
module VagrantPlugins
|
|
||||||
module ProviderVirtualBox
|
|
||||||
module Action
|
|
||||||
class ProvisionerCleanup
|
|
||||||
def initialize(app, env)
|
|
||||||
@app = app
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
|
||||||
# Instantiate all the enabled provisioners
|
|
||||||
provisioners = env[:machine].config.vm.provisioners.map do |provisioner|
|
|
||||||
provisioner.provisioner.new(env, provisioner.config)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Call cleanup on each
|
|
||||||
provisioners.each do |instance|
|
|
||||||
instance.cleanup
|
|
||||||
end
|
|
||||||
|
|
||||||
@app.call(env)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -14,7 +14,7 @@ module VagrantPlugins
|
||||||
Provider
|
Provider
|
||||||
end
|
end
|
||||||
|
|
||||||
config(:virtualbox, :provider => :virtualbox) do
|
config(:virtualbox, :provider) do
|
||||||
require File.expand_path("../config", __FILE__)
|
require File.expand_path("../config", __FILE__)
|
||||||
Config
|
Config
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module Chef
|
||||||
|
module Config
|
||||||
|
class Base < Vagrant.plugin("2", :config)
|
||||||
|
# Shared config
|
||||||
|
attr_accessor :node_name
|
||||||
|
attr_accessor :provisioning_path
|
||||||
|
attr_accessor :log_level
|
||||||
|
attr_accessor :json
|
||||||
|
attr_accessor :http_proxy
|
||||||
|
attr_accessor :http_proxy_user
|
||||||
|
attr_accessor :http_proxy_pass
|
||||||
|
attr_accessor :https_proxy
|
||||||
|
attr_accessor :https_proxy_user
|
||||||
|
attr_accessor :https_proxy_pass
|
||||||
|
attr_accessor :no_proxy
|
||||||
|
attr_accessor :binary_path
|
||||||
|
attr_accessor :binary_env
|
||||||
|
attr_accessor :attempts
|
||||||
|
attr_accessor :arguments
|
||||||
|
attr_writer :run_list
|
||||||
|
|
||||||
|
# Provide defaults in such a way that they won't override the instance
|
||||||
|
# variable. This is so merging continues to work properly.
|
||||||
|
def attempts; @attempts || 1; end
|
||||||
|
def json; @json ||= {}; end
|
||||||
|
def log_level; @log_level || :info; end
|
||||||
|
|
||||||
|
# This returns the json that is merged with the defaults and the
|
||||||
|
# user set data.
|
||||||
|
def merged_json
|
||||||
|
original = { :instance_role => "vagrant" }
|
||||||
|
original[:run_list] = @run_list if @run_list
|
||||||
|
original.merge(json || {})
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the run list, but also sets it up to be empty if it
|
||||||
|
# hasn't been defined already.
|
||||||
|
def run_list
|
||||||
|
@run_list ||= []
|
||||||
|
end
|
||||||
|
|
||||||
|
# Adds a recipe to the run list
|
||||||
|
def add_recipe(name)
|
||||||
|
name = "recipe[#{name}]" unless name =~ /^recipe\[(.+?)\]$/
|
||||||
|
run_list << name
|
||||||
|
end
|
||||||
|
|
||||||
|
# Adds a role to the run list
|
||||||
|
def add_role(name)
|
||||||
|
name = "role[#{name}]" unless name =~ /^role\[(.+?)\]$/
|
||||||
|
run_list << name
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate(env, errors)
|
||||||
|
super
|
||||||
|
|
||||||
|
errors.add(I18n.t("vagrant.config.chef.vagrant_as_json_key")) if json.has_key?(:vagrant)
|
||||||
|
end
|
||||||
|
|
||||||
|
def instance_variables_hash
|
||||||
|
# Overridden so that the 'json' key could be removed, since its just
|
||||||
|
# merged into the config anyways
|
||||||
|
result = super
|
||||||
|
result.delete("json")
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,35 @@
|
||||||
|
require File.expand_path("../base", __FILE__)
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module Chef
|
||||||
|
module Config
|
||||||
|
class ChefClient < Base
|
||||||
|
attr_accessor :chef_server_url
|
||||||
|
attr_accessor :validation_key_path
|
||||||
|
attr_accessor :validation_client_name
|
||||||
|
attr_accessor :client_key_path
|
||||||
|
attr_accessor :file_cache_path
|
||||||
|
attr_accessor :file_backup_path
|
||||||
|
attr_accessor :environment
|
||||||
|
attr_accessor :encrypted_data_bag_secret_key_path
|
||||||
|
attr_accessor :encrypted_data_bag_secret
|
||||||
|
|
||||||
|
# Provide defaults in such a way that they won't override the instance
|
||||||
|
# variable. This is so merging continues to work properly.
|
||||||
|
def validation_client_name; @validation_client_name || "chef-validator"; end
|
||||||
|
def client_key_path; @client_key_path || "/etc/chef/client.pem"; end
|
||||||
|
def file_cache_path; @file_cache_path || "/srv/chef/file_store"; end
|
||||||
|
def file_backup_path; @file_backup_path || "/srv/chef/cache"; end
|
||||||
|
def encrypted_data_bag_secret; @encrypted_data_bag_secret || "/tmp/encrypted_data_bag_secret"; end
|
||||||
|
|
||||||
|
def validate(env, errors)
|
||||||
|
super
|
||||||
|
|
||||||
|
errors.add(I18n.t("vagrant.config.chef.server_url_empty")) if !chef_server_url || chef_server_url.strip == ""
|
||||||
|
errors.add(I18n.t("vagrant.config.chef.validation_key_path")) if !validation_key_path
|
||||||
|
errors.add(I18n.t("vagrant.config.chef.run_list_empty")) if @run_list && @run_list.empty?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,49 @@
|
||||||
|
require File.expand_path("../base", __FILE__)
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module Chef
|
||||||
|
module Config
|
||||||
|
class ChefSolo < Base
|
||||||
|
attr_accessor :cookbooks_path
|
||||||
|
attr_accessor :roles_path
|
||||||
|
attr_accessor :data_bags_path
|
||||||
|
attr_accessor :recipe_url
|
||||||
|
attr_accessor :nfs
|
||||||
|
attr_accessor :encrypted_data_bag_secret_key_path
|
||||||
|
attr_accessor :encrypted_data_bag_secret
|
||||||
|
|
||||||
|
def encrypted_data_bag_secret; @encrypted_data_bag_secret || "/tmp/encrypted_data_bag_secret"; end
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
super
|
||||||
|
|
||||||
|
@__default = ["cookbooks", [:vm, "cookbooks"]]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Provide defaults in such a way that they won't override the instance
|
||||||
|
# variable. This is so merging continues to work properly.
|
||||||
|
def cookbooks_path
|
||||||
|
@cookbooks_path || _default_cookbook_path
|
||||||
|
end
|
||||||
|
|
||||||
|
# This stores a reference to the default cookbook path which is used
|
||||||
|
# later. Do not use this publicly. I apologize for not making it
|
||||||
|
# "protected" but it has to be called by Vagrant internals later.
|
||||||
|
def _default_cookbook_path
|
||||||
|
@__default
|
||||||
|
end
|
||||||
|
|
||||||
|
def nfs
|
||||||
|
@nfs || false
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate(env, errors)
|
||||||
|
super
|
||||||
|
|
||||||
|
errors.add(I18n.t("vagrant.config.chef.cookbooks_path_empty")) if !cookbooks_path || [cookbooks_path].flatten.empty?
|
||||||
|
errors.add(I18n.t("vagrant.config.chef.run_list_empty")) if !run_list || run_list.empty?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -9,12 +9,22 @@ module VagrantPlugins
|
||||||
Chef via `chef-solo` or `chef-client`.
|
Chef via `chef-solo` or `chef-client`.
|
||||||
DESC
|
DESC
|
||||||
|
|
||||||
provisioner("chef_solo") do
|
config(:chef_solo, :provisioner) do
|
||||||
|
require File.expand_path("../config/chef_solo", __FILE__)
|
||||||
|
Config::ChefSolo
|
||||||
|
end
|
||||||
|
|
||||||
|
config(:chef_client, :provisioner) do
|
||||||
|
require File.expand_path("../config/chef_client", __FILE__)
|
||||||
|
Config::ChefClient
|
||||||
|
end
|
||||||
|
|
||||||
|
provisioner(:chef_solo) do
|
||||||
require File.expand_path("../provisioner/chef_solo", __FILE__)
|
require File.expand_path("../provisioner/chef_solo", __FILE__)
|
||||||
Provisioner::ChefSolo
|
Provisioner::ChefSolo
|
||||||
end
|
end
|
||||||
|
|
||||||
provisioner("chef_client") do
|
provisioner(:chef_client) do
|
||||||
require File.expand_path("../provisioner/chef_client", __FILE__)
|
require File.expand_path("../provisioner/chef_client", __FILE__)
|
||||||
Provisioner::ChefClient
|
Provisioner::ChefClient
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
require 'tempfile'
|
require 'tempfile'
|
||||||
|
|
||||||
|
require "vagrant/util/counter"
|
||||||
require "vagrant/util/template_renderer"
|
require "vagrant/util/template_renderer"
|
||||||
|
|
||||||
module VagrantPlugins
|
module VagrantPlugins
|
||||||
|
@ -9,9 +10,13 @@ module VagrantPlugins
|
||||||
# chef-solo and chef-client provisioning are stored. This is **not an actual
|
# chef-solo and chef-client provisioning are stored. This is **not an actual
|
||||||
# provisioner**. Instead, {ChefSolo} or {ChefServer} should be used.
|
# provisioner**. Instead, {ChefSolo} or {ChefServer} should be used.
|
||||||
class Base < Vagrant.plugin("2", :provisioner)
|
class Base < Vagrant.plugin("2", :provisioner)
|
||||||
|
class ChefError < Vagrant::Errors::VagrantError
|
||||||
|
error_namespace("vagrant.provisioners.chef")
|
||||||
|
end
|
||||||
|
|
||||||
include Vagrant::Util::Counter
|
include Vagrant::Util::Counter
|
||||||
|
|
||||||
def initialize(env, config)
|
def initialize(machine, config)
|
||||||
super
|
super
|
||||||
|
|
||||||
config.provisioning_path ||= "/tmp/vagrant-chef-#{get_and_update_counter(:provisioning_path)}"
|
config.provisioning_path ||= "/tmp/vagrant-chef-#{get_and_update_counter(:provisioning_path)}"
|
||||||
|
@ -20,36 +25,37 @@ module VagrantPlugins
|
||||||
def verify_binary(binary)
|
def verify_binary(binary)
|
||||||
# Checks for the existence of chef binary and error if it
|
# Checks for the existence of chef binary and error if it
|
||||||
# doesn't exist.
|
# doesn't exist.
|
||||||
env[:machine].communicate.sudo("which #{binary}",
|
@machine.communicate.sudo(
|
||||||
:error_class => ChefError,
|
"which #{binary}",
|
||||||
:error_key => :chef_not_detected,
|
:error_class => ChefError,
|
||||||
:binary => binary)
|
:error_key => :chef_not_detected,
|
||||||
|
:binary => binary)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the path to the Chef binary, taking into account the
|
# Returns the path to the Chef binary, taking into account the
|
||||||
# `binary_path` configuration option.
|
# `binary_path` configuration option.
|
||||||
def chef_binary_path(binary)
|
def chef_binary_path(binary)
|
||||||
return binary if !config.binary_path
|
return binary if !@config.binary_path
|
||||||
return File.join(config.binary_path, binary)
|
return File.join(@config.binary_path, binary)
|
||||||
end
|
end
|
||||||
|
|
||||||
def chown_provisioning_folder
|
def chown_provisioning_folder
|
||||||
env[:machine].communicate.tap do |comm|
|
@machine.communicate.tap do |comm|
|
||||||
comm.sudo("mkdir -p #{config.provisioning_path}")
|
comm.sudo("mkdir -p #{@config.provisioning_path}")
|
||||||
comm.sudo("chown #{env[:machine].config.ssh.username} #{config.provisioning_path}")
|
comm.sudo("chown #{@machine.config.ssh.username} #{@config.provisioning_path}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup_config(template, filename, template_vars)
|
def setup_config(template, filename, template_vars)
|
||||||
config_file = Vagrant::Util::TemplateRenderer.render(template, {
|
config_file = Vagrant::Util::TemplateRenderer.render(template, {
|
||||||
:log_level => config.log_level.to_sym,
|
:log_level => @config.log_level.to_sym,
|
||||||
:http_proxy => config.http_proxy,
|
:http_proxy => @config.http_proxy,
|
||||||
:http_proxy_user => config.http_proxy_user,
|
:http_proxy_user => @config.http_proxy_user,
|
||||||
:http_proxy_pass => config.http_proxy_pass,
|
:http_proxy_pass => @config.http_proxy_pass,
|
||||||
:https_proxy => config.https_proxy,
|
:https_proxy => @config.https_proxy,
|
||||||
:https_proxy_user => config.https_proxy_user,
|
:https_proxy_user => @config.https_proxy_user,
|
||||||
:https_proxy_pass => config.https_proxy_pass,
|
:https_proxy_pass => @config.https_proxy_pass,
|
||||||
:no_proxy => config.no_proxy
|
:no_proxy => @config.no_proxy
|
||||||
}.merge(template_vars))
|
}.merge(template_vars))
|
||||||
|
|
||||||
# Create a temporary file to store the data so we
|
# Create a temporary file to store the data so we
|
||||||
|
@ -59,17 +65,17 @@ module VagrantPlugins
|
||||||
temp.close
|
temp.close
|
||||||
|
|
||||||
remote_file = File.join(config.provisioning_path, filename)
|
remote_file = File.join(config.provisioning_path, filename)
|
||||||
env[:machine].communicate.tap do |comm|
|
@machine.communicate.tap do |comm|
|
||||||
comm.sudo("rm #{remote_file}", :error_check => false)
|
comm.sudo("rm #{remote_file}", :error_check => false)
|
||||||
comm.upload(temp.path, remote_file)
|
comm.upload(temp.path, remote_file)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup_json
|
def setup_json
|
||||||
env[:ui].info I18n.t("vagrant.provisioners.chef.json")
|
@machine.env.ui.info I18n.t("vagrant.provisioners.chef.json")
|
||||||
|
|
||||||
# Get the JSON that we're going to expose to Chef
|
# Get the JSON that we're going to expose to Chef
|
||||||
json = JSON.pretty_generate(config.merged_json)
|
json = JSON.pretty_generate(@config.merged_json)
|
||||||
|
|
||||||
# Create a temporary file to store the data so we
|
# Create a temporary file to store the data so we
|
||||||
# can upload it
|
# can upload it
|
||||||
|
@ -77,78 +83,7 @@ module VagrantPlugins
|
||||||
temp.write(json)
|
temp.write(json)
|
||||||
temp.close
|
temp.close
|
||||||
|
|
||||||
env[:machine].communicate.upload(temp.path, File.join(config.provisioning_path, "dna.json"))
|
@machine.communicate.upload(temp.path, File.join(@config.provisioning_path, "dna.json"))
|
||||||
end
|
|
||||||
|
|
||||||
class ChefError < Vagrant::Errors::VagrantError
|
|
||||||
error_namespace("vagrant.provisioners.chef")
|
|
||||||
end
|
|
||||||
|
|
||||||
# This is the configuration which is available through `config.chef`
|
|
||||||
class Config < Vagrant.plugin("2", :config)
|
|
||||||
# Shared config
|
|
||||||
attr_accessor :node_name
|
|
||||||
attr_accessor :provisioning_path
|
|
||||||
attr_accessor :log_level
|
|
||||||
attr_accessor :json
|
|
||||||
attr_accessor :http_proxy
|
|
||||||
attr_accessor :http_proxy_user
|
|
||||||
attr_accessor :http_proxy_pass
|
|
||||||
attr_accessor :https_proxy
|
|
||||||
attr_accessor :https_proxy_user
|
|
||||||
attr_accessor :https_proxy_pass
|
|
||||||
attr_accessor :no_proxy
|
|
||||||
attr_accessor :binary_path
|
|
||||||
attr_accessor :binary_env
|
|
||||||
attr_accessor :attempts
|
|
||||||
attr_accessor :arguments
|
|
||||||
attr_writer :run_list
|
|
||||||
|
|
||||||
# Provide defaults in such a way that they won't override the instance
|
|
||||||
# variable. This is so merging continues to work properly.
|
|
||||||
def attempts; @attempts || 1; end
|
|
||||||
def json; @json ||= {}; end
|
|
||||||
def log_level; @log_level || :info; end
|
|
||||||
|
|
||||||
# This returns the json that is merged with the defaults and the
|
|
||||||
# user set data.
|
|
||||||
def merged_json
|
|
||||||
original = { :instance_role => "vagrant" }
|
|
||||||
original[:run_list] = @run_list if @run_list
|
|
||||||
original.merge(json || {})
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the run list, but also sets it up to be empty if it
|
|
||||||
# hasn't been defined already.
|
|
||||||
def run_list
|
|
||||||
@run_list ||= []
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adds a recipe to the run list
|
|
||||||
def add_recipe(name)
|
|
||||||
name = "recipe[#{name}]" unless name =~ /^recipe\[(.+?)\]$/
|
|
||||||
run_list << name
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adds a role to the run list
|
|
||||||
def add_role(name)
|
|
||||||
name = "role[#{name}]" unless name =~ /^role\[(.+?)\]$/
|
|
||||||
run_list << name
|
|
||||||
end
|
|
||||||
|
|
||||||
def validate(env, errors)
|
|
||||||
super
|
|
||||||
|
|
||||||
errors.add(I18n.t("vagrant.config.chef.vagrant_as_json_key")) if json.has_key?(:vagrant)
|
|
||||||
end
|
|
||||||
|
|
||||||
def instance_variables_hash
|
|
||||||
# Overridden so that the 'json' key could be removed, since its just
|
|
||||||
# merged into the config anyways
|
|
||||||
result = super
|
|
||||||
result.delete("json")
|
|
||||||
result
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,42 +8,10 @@ module VagrantPlugins
|
||||||
# This class implements provisioning via chef-client, allowing provisioning
|
# This class implements provisioning via chef-client, allowing provisioning
|
||||||
# with a chef server.
|
# with a chef server.
|
||||||
class ChefClient < Base
|
class ChefClient < Base
|
||||||
class Config < Base::Config
|
def configure(root_config)
|
||||||
attr_accessor :chef_server_url
|
raise ChefError, :server_validation_key_required if @config.validation_key_path.nil?
|
||||||
attr_accessor :validation_key_path
|
|
||||||
attr_accessor :validation_client_name
|
|
||||||
attr_accessor :client_key_path
|
|
||||||
attr_accessor :file_cache_path
|
|
||||||
attr_accessor :file_backup_path
|
|
||||||
attr_accessor :environment
|
|
||||||
attr_accessor :encrypted_data_bag_secret_key_path
|
|
||||||
attr_accessor :encrypted_data_bag_secret
|
|
||||||
|
|
||||||
# Provide defaults in such a way that they won't override the instance
|
|
||||||
# variable. This is so merging continues to work properly.
|
|
||||||
def validation_client_name; @validation_client_name || "chef-validator"; end
|
|
||||||
def client_key_path; @client_key_path || "/etc/chef/client.pem"; end
|
|
||||||
def file_cache_path; @file_cache_path || "/srv/chef/file_store"; end
|
|
||||||
def file_backup_path; @file_backup_path || "/srv/chef/cache"; end
|
|
||||||
def encrypted_data_bag_secret; @encrypted_data_bag_secret || "/tmp/encrypted_data_bag_secret"; end
|
|
||||||
|
|
||||||
def validate(env, errors)
|
|
||||||
super
|
|
||||||
|
|
||||||
errors.add(I18n.t("vagrant.config.chef.server_url_empty")) if !chef_server_url || chef_server_url.strip == ""
|
|
||||||
errors.add(I18n.t("vagrant.config.chef.validation_key_path")) if !validation_key_path
|
|
||||||
errors.add(I18n.t("vagrant.config.chef.run_list_empty")) if @run_list && @run_list.empty?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.config_class
|
|
||||||
Config
|
|
||||||
end
|
|
||||||
|
|
||||||
def prepare
|
|
||||||
raise ChefError, :server_validation_key_required if config.validation_key_path.nil?
|
|
||||||
raise ChefError, :server_validation_key_doesnt_exist if !File.file?(validation_key_path)
|
raise ChefError, :server_validation_key_doesnt_exist if !File.file?(validation_key_path)
|
||||||
raise ChefError, :server_url_required if config.chef_server_url.nil?
|
raise ChefError, :server_url_required if @config.chef_server_url.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def provision!
|
def provision!
|
||||||
|
@ -51,63 +19,63 @@ module VagrantPlugins
|
||||||
chown_provisioning_folder
|
chown_provisioning_folder
|
||||||
create_client_key_folder
|
create_client_key_folder
|
||||||
upload_validation_key
|
upload_validation_key
|
||||||
upload_encrypted_data_bag_secret if config.encrypted_data_bag_secret_key_path
|
upload_encrypted_data_bag_secret if @config.encrypted_data_bag_secret_key_path
|
||||||
setup_json
|
setup_json
|
||||||
setup_server_config
|
setup_server_config
|
||||||
run_chef_client
|
run_chef_client
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_client_key_folder
|
def create_client_key_folder
|
||||||
env[:ui].info I18n.t("vagrant.provisioners.chef.client_key_folder")
|
@machine.env.ui.info I18n.t("vagrant.provisioners.chef.client_key_folder")
|
||||||
path = Pathname.new(config.client_key_path)
|
path = Pathname.new(@config.client_key_path)
|
||||||
|
|
||||||
env[:machine].communicate.sudo("mkdir -p #{path.dirname}")
|
@machine.communicate.sudo("mkdir -p #{path.dirname}")
|
||||||
end
|
end
|
||||||
|
|
||||||
def upload_validation_key
|
def upload_validation_key
|
||||||
env[:ui].info I18n.t("vagrant.provisioners.chef.upload_validation_key")
|
@machine.env.ui.info I18n.t("vagrant.provisioners.chef.upload_validation_key")
|
||||||
env[:machine].communicate.upload(validation_key_path, guest_validation_key_path)
|
@machine.communicate.upload(validation_key_path, guest_validation_key_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def upload_encrypted_data_bag_secret
|
def upload_encrypted_data_bag_secret
|
||||||
env[:ui].info I18n.t("vagrant.provisioners.chef.upload_encrypted_data_bag_secret_key")
|
@machine.env.ui.info I18n.t("vagrant.provisioners.chef.upload_encrypted_data_bag_secret_key")
|
||||||
env[:machine].communicate.upload(encrypted_data_bag_secret_key_path,
|
@machine.communicate.upload(encrypted_data_bag_secret_key_path,
|
||||||
config.encrypted_data_bag_secret)
|
@config.encrypted_data_bag_secret)
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup_server_config
|
def setup_server_config
|
||||||
setup_config("provisioners/chef_client/client", "client.rb", {
|
setup_config("provisioners/chef_client/client", "client.rb", {
|
||||||
:node_name => config.node_name,
|
:node_name => @config.node_name,
|
||||||
:chef_server_url => config.chef_server_url,
|
:chef_server_url => @config.chef_server_url,
|
||||||
:validation_client_name => config.validation_client_name,
|
:validation_client_name => @config.validation_client_name,
|
||||||
:validation_key => guest_validation_key_path,
|
:validation_key => guest_validation_key_path,
|
||||||
:client_key => config.client_key_path,
|
:client_key => @config.client_key_path,
|
||||||
:file_cache_path => config.file_cache_path,
|
:file_cache_path => @config.file_cache_path,
|
||||||
:file_backup_path => config.file_backup_path,
|
:file_backup_path => @config.file_backup_path,
|
||||||
:environment => config.environment,
|
:environment => @config.environment,
|
||||||
:encrypted_data_bag_secret => config.encrypted_data_bag_secret
|
:encrypted_data_bag_secret => @config.encrypted_data_bag_secret
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_chef_client
|
def run_chef_client
|
||||||
command_env = config.binary_env ? "#{config.binary_env} " : ""
|
command_env = @config.binary_env ? "#{@config.binary_env} " : ""
|
||||||
command_args = config.arguments ? " #{config.arguments}" : ""
|
command_args = @config.arguments ? " #{@config.arguments}" : ""
|
||||||
command = "#{command_env}#{chef_binary_path("chef-client")} -c #{config.provisioning_path}/client.rb -j #{config.provisioning_path}/dna.json #{command_args}"
|
command = "#{command_env}#{chef_binary_path("chef-client")} -c #{@config.provisioning_path}/client.rb -j #{@config.provisioning_path}/dna.json #{command_args}"
|
||||||
|
|
||||||
config.attempts.times do |attempt|
|
@config.attempts.times do |attempt|
|
||||||
if attempt == 0
|
if attempt == 0
|
||||||
env[:ui].info I18n.t("vagrant.provisioners.chef.running_client")
|
@machine.env.ui.info I18n.t("vagrant.provisioners.chef.running_client")
|
||||||
else
|
else
|
||||||
env[:ui].info I18n.t("vagrant.provisioners.chef.running_client_again")
|
@machine.env.ui.info I18n.t("vagrant.provisioners.chef.running_client_again")
|
||||||
end
|
end
|
||||||
|
|
||||||
exit_status = env[:machine].communicate.sudo(command, :error_check => false) do |type, data|
|
exit_status = @machine.communicate.sudo(command, :error_check => false) do |type, data|
|
||||||
# Output the data with the proper color based on the stream.
|
# Output the data with the proper color based on the stream.
|
||||||
color = type == :stdout ? :green : :red
|
color = type == :stdout ? :green : :red
|
||||||
|
|
||||||
# Note: Be sure to chomp the data to avoid the newlines that the
|
# Note: Be sure to chomp the data to avoid the newlines that the
|
||||||
# Chef outputs.
|
# Chef outputs.
|
||||||
env[:ui].info(data.chomp, :color => color, :prefix => false)
|
@machine.env.ui.info(data.chomp, :color => color, :prefix => false)
|
||||||
end
|
end
|
||||||
|
|
||||||
# There is no need to run Chef again if it converges
|
# There is no need to run Chef again if it converges
|
||||||
|
@ -119,15 +87,15 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
|
|
||||||
def validation_key_path
|
def validation_key_path
|
||||||
File.expand_path(config.validation_key_path, env[:root_path])
|
File.expand_path(@config.validation_key_path, @machine.env.root_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def encrypted_data_bag_secret_key_path
|
def encrypted_data_bag_secret_key_path
|
||||||
File.expand_path(config.encrypted_data_bag_secret_key_path, env[:root_path])
|
File.expand_path(@config.encrypted_data_bag_secret_key_path, @machine.env.root_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def guest_validation_key_path
|
def guest_validation_key_path
|
||||||
File.join(config.provisioning_path, "validation.pem")
|
File.join(@config.provisioning_path, "validation.pem")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
require "log4r"
|
require "log4r"
|
||||||
|
|
||||||
|
require "vagrant/util/counter"
|
||||||
|
|
||||||
require File.expand_path("../base", __FILE__)
|
require File.expand_path("../base", __FILE__)
|
||||||
|
|
||||||
module VagrantPlugins
|
module VagrantPlugins
|
||||||
|
@ -10,72 +12,26 @@ module VagrantPlugins
|
||||||
extend Vagrant::Util::Counter
|
extend Vagrant::Util::Counter
|
||||||
include Vagrant::Util::Counter
|
include Vagrant::Util::Counter
|
||||||
|
|
||||||
class Config < Base::Config
|
|
||||||
attr_accessor :cookbooks_path
|
|
||||||
attr_accessor :roles_path
|
|
||||||
attr_accessor :data_bags_path
|
|
||||||
attr_accessor :recipe_url
|
|
||||||
attr_accessor :nfs
|
|
||||||
attr_accessor :encrypted_data_bag_secret_key_path
|
|
||||||
attr_accessor :encrypted_data_bag_secret
|
|
||||||
|
|
||||||
def encrypted_data_bag_secret; @encrypted_data_bag_secret || "/tmp/encrypted_data_bag_secret"; end
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
super
|
|
||||||
|
|
||||||
@__default = ["cookbooks", [:vm, "cookbooks"]]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Provide defaults in such a way that they won't override the instance
|
|
||||||
# variable. This is so merging continues to work properly.
|
|
||||||
def cookbooks_path
|
|
||||||
@cookbooks_path || _default_cookbook_path
|
|
||||||
end
|
|
||||||
|
|
||||||
# This stores a reference to the default cookbook path which is used
|
|
||||||
# later. Do not use this publicly. I apologize for not making it
|
|
||||||
# "protected" but it has to be called by Vagrant internals later.
|
|
||||||
def _default_cookbook_path
|
|
||||||
@__default
|
|
||||||
end
|
|
||||||
|
|
||||||
def nfs
|
|
||||||
@nfs || false
|
|
||||||
end
|
|
||||||
|
|
||||||
def validate(env, errors)
|
|
||||||
super
|
|
||||||
|
|
||||||
errors.add(I18n.t("vagrant.config.chef.cookbooks_path_empty")) if !cookbooks_path || [cookbooks_path].flatten.empty?
|
|
||||||
errors.add(I18n.t("vagrant.config.chef.run_list_empty")) if !run_list || run_list.empty?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_reader :cookbook_folders
|
attr_reader :cookbook_folders
|
||||||
attr_reader :role_folders
|
attr_reader :role_folders
|
||||||
attr_reader :data_bags_folders
|
attr_reader :data_bags_folders
|
||||||
|
|
||||||
def self.config_class
|
def initialize(machine, config)
|
||||||
Config
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(env, config)
|
|
||||||
super
|
super
|
||||||
@logger = Log4r::Logger.new("vagrant::provisioners::chef_solo")
|
@logger = Log4r::Logger.new("vagrant::provisioners::chef_solo")
|
||||||
end
|
end
|
||||||
|
|
||||||
def prepare
|
def configure(root_config)
|
||||||
@cookbook_folders = expanded_folders(config.cookbooks_path, "cookbooks")
|
@cookbook_folders = expanded_folders(@config.cookbooks_path, "cookbooks")
|
||||||
@role_folders = expanded_folders(config.roles_path, "roles")
|
@role_folders = expanded_folders(@config.roles_path, "roles")
|
||||||
@data_bags_folders = expanded_folders(config.data_bags_path, "data_bags")
|
@data_bags_folders = expanded_folders(@config.data_bags_path, "data_bags")
|
||||||
|
|
||||||
share_folders("csc", @cookbook_folders)
|
share_folders(root_config, "csc", @cookbook_folders)
|
||||||
share_folders("csr", @role_folders)
|
share_folders(root_config, "csr", @role_folders)
|
||||||
share_folders("csdb", @data_bags_folders)
|
share_folders(root_config, "csdb", @data_bags_folders)
|
||||||
end
|
end
|
||||||
|
|
||||||
def provision!
|
def provision
|
||||||
# Verify that the proper shared folders exist.
|
# Verify that the proper shared folders exist.
|
||||||
check = []
|
check = []
|
||||||
[@cookbook_folders, @role_folders, @data_bags_folders].each do |folders|
|
[@cookbook_folders, @role_folders, @data_bags_folders].each do |folders|
|
||||||
|
@ -91,7 +47,7 @@ module VagrantPlugins
|
||||||
|
|
||||||
verify_binary(chef_binary_path("chef-solo"))
|
verify_binary(chef_binary_path("chef-solo"))
|
||||||
chown_provisioning_folder
|
chown_provisioning_folder
|
||||||
upload_encrypted_data_bag_secret if config.encrypted_data_bag_secret_key_path
|
upload_encrypted_data_bag_secret if @config.encrypted_data_bag_secret_key_path
|
||||||
setup_json
|
setup_json
|
||||||
setup_solo_config
|
setup_solo_config
|
||||||
run_chef_solo
|
run_chef_solo
|
||||||
|
@ -116,22 +72,22 @@ module VagrantPlugins
|
||||||
remote_path = nil
|
remote_path = nil
|
||||||
if type == :host
|
if type == :host
|
||||||
# Get the expanded path that the host path points to
|
# Get the expanded path that the host path points to
|
||||||
local_path = File.expand_path(path, env[:root_path])
|
local_path = File.expand_path(path, @machine.env.root_path)
|
||||||
|
|
||||||
# Super hacky but if we're expanded the default cookbook paths,
|
# Super hacky but if we're expanded the default cookbook paths,
|
||||||
# and one of the host paths doesn't exist, then just ignore it,
|
# and one of the host paths doesn't exist, then just ignore it,
|
||||||
# because that is fine.
|
# because that is fine.
|
||||||
if paths.equal?(config._default_cookbook_path) && !File.directory?(local_path)
|
if paths.equal?(@config._default_cookbook_path) && !File.directory?(local_path)
|
||||||
@logger.info("'cookbooks' folder doesn't exist on defaults. Ignoring.")
|
@logger.info("'cookbooks' folder doesn't exist on defaults. Ignoring.")
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
# Path exists on the host, setup the remote path
|
# Path exists on the host, setup the remote path
|
||||||
remote_path = "#{config.provisioning_path}/chef-solo-#{get_and_update_counter(:cookbooks_path)}"
|
remote_path = "#{@config.provisioning_path}/chef-solo-#{get_and_update_counter(:cookbooks_path)}"
|
||||||
else
|
else
|
||||||
# Path already exists on the virtual machine. Expand it
|
# Path already exists on the virtual machine. Expand it
|
||||||
# relative to where we're provisioning.
|
# relative to where we're provisioning.
|
||||||
remote_path = File.expand_path(path, config.provisioning_path)
|
remote_path = File.expand_path(path, @config.provisioning_path)
|
||||||
|
|
||||||
# Remove drive letter if running on a windows host. This is a bit
|
# Remove drive letter if running on a windows host. This is a bit
|
||||||
# of a hack but is the most portable way I can think of at the moment
|
# of a hack but is the most portable way I can think of at the moment
|
||||||
|
@ -152,20 +108,20 @@ module VagrantPlugins
|
||||||
|
|
||||||
# Shares the given folders with the given prefix. The folders should
|
# Shares the given folders with the given prefix. The folders should
|
||||||
# be of the structure resulting from the `expanded_folders` function.
|
# be of the structure resulting from the `expanded_folders` function.
|
||||||
def share_folders(prefix, folders)
|
def share_folders(root_config, prefix, folders)
|
||||||
folders.each do |type, local_path, remote_path|
|
folders.each do |type, local_path, remote_path|
|
||||||
if type == :host
|
if type == :host
|
||||||
env[:machine].config.vm.share_folder(
|
root_config.vm.share_folder(
|
||||||
"v-#{prefix}-#{self.class.get_and_update_counter(:shared_folder)}",
|
"v-#{prefix}-#{self.class.get_and_update_counter(:shared_folder)}",
|
||||||
remote_path, local_path, :nfs => config.nfs)
|
remote_path, local_path, :nfs => @config.nfs)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def upload_encrypted_data_bag_secret
|
def upload_encrypted_data_bag_secret
|
||||||
env[:ui].info I18n.t("vagrant.provisioners.chef.upload_encrypted_data_bag_secret_key")
|
@machine.env.ui.info I18n.t("vagrant.provisioners.chef.upload_encrypted_data_bag_secret_key")
|
||||||
env[:machine].communicate.upload(encrypted_data_bag_secret_key_path,
|
@machine.communicate.upload(encrypted_data_bag_secret_key_path,
|
||||||
config.encrypted_data_bag_secret)
|
@config.encrypted_data_bag_secret)
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup_solo_config
|
def setup_solo_config
|
||||||
|
@ -174,35 +130,35 @@ module VagrantPlugins
|
||||||
data_bags_path = guest_paths(@data_bags_folders).first
|
data_bags_path = guest_paths(@data_bags_folders).first
|
||||||
|
|
||||||
setup_config("provisioners/chef_solo/solo", "solo.rb", {
|
setup_config("provisioners/chef_solo/solo", "solo.rb", {
|
||||||
:node_name => config.node_name,
|
:node_name => @config.node_name,
|
||||||
:provisioning_path => config.provisioning_path,
|
:provisioning_path => @config.provisioning_path,
|
||||||
:cookbooks_path => cookbooks_path,
|
:cookbooks_path => cookbooks_path,
|
||||||
:recipe_url => config.recipe_url,
|
:recipe_url => @config.recipe_url,
|
||||||
:roles_path => roles_path,
|
:roles_path => roles_path,
|
||||||
:data_bags_path => data_bags_path,
|
:data_bags_path => data_bags_path,
|
||||||
:encrypted_data_bag_secret => config.encrypted_data_bag_secret,
|
:encrypted_data_bag_secret => @config.encrypted_data_bag_secret,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_chef_solo
|
def run_chef_solo
|
||||||
command_env = config.binary_env ? "#{config.binary_env} " : ""
|
command_env = @config.binary_env ? "#{@config.binary_env} " : ""
|
||||||
command_args = config.arguments ? " #{config.arguments}" : ""
|
command_args = @config.arguments ? " #{@config.arguments}" : ""
|
||||||
command = "#{command_env}#{chef_binary_path("chef-solo")} -c #{config.provisioning_path}/solo.rb -j #{config.provisioning_path}/dna.json #{command_args}"
|
command = "#{command_env}#{chef_binary_path("chef-solo")} -c #{@config.provisioning_path}/solo.rb -j #{@config.provisioning_path}/dna.json #{command_args}"
|
||||||
|
|
||||||
config.attempts.times do |attempt|
|
@config.attempts.times do |attempt|
|
||||||
if attempt == 0
|
if attempt == 0
|
||||||
env[:ui].info I18n.t("vagrant.provisioners.chef.running_solo")
|
@machine.env.ui.info I18n.t("vagrant.provisioners.chef.running_solo")
|
||||||
else
|
else
|
||||||
env[:ui].info I18n.t("vagrant.provisioners.chef.running_solo_again")
|
@machine.env.ui.info I18n.t("vagrant.provisioners.chef.running_solo_again")
|
||||||
end
|
end
|
||||||
|
|
||||||
exit_status = env[:machine].communicate.sudo(command, :error_check => false) do |type, data|
|
exit_status = @machine.communicate.sudo(command, :error_check => false) do |type, data|
|
||||||
# Output the data with the proper color based on the stream.
|
# Output the data with the proper color based on the stream.
|
||||||
color = type == :stdout ? :green : :red
|
color = type == :stdout ? :green : :red
|
||||||
|
|
||||||
# Note: Be sure to chomp the data to avoid the newlines that the
|
# Note: Be sure to chomp the data to avoid the newlines that the
|
||||||
# Chef outputs.
|
# Chef outputs.
|
||||||
env[:ui].info(data.chomp, :color => color, :prefix => false)
|
@machine.env.ui.info(data.chomp, :color => color, :prefix => false)
|
||||||
end
|
end
|
||||||
|
|
||||||
# There is no need to run Chef again if it converges
|
# There is no need to run Chef again if it converges
|
||||||
|
@ -216,14 +172,14 @@ module VagrantPlugins
|
||||||
def verify_shared_folders(folders)
|
def verify_shared_folders(folders)
|
||||||
folders.each do |folder|
|
folders.each do |folder|
|
||||||
@logger.debug("Checking for shared folder: #{folder}")
|
@logger.debug("Checking for shared folder: #{folder}")
|
||||||
if !env[:machine].communicate.test("test -d #{folder}")
|
if !@machine.communicate.test("test -d #{folder}")
|
||||||
raise ChefError, :missing_shared_folders
|
raise ChefError, :missing_shared_folders
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def encrypted_data_bag_secret_key_path
|
def encrypted_data_bag_secret_key_path
|
||||||
File.expand_path(config.encrypted_data_bag_secret_key_path, env[:root_path])
|
File.expand_path(@config.encrypted_data_bag_secret_key_path, @machine.env.root_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module Puppet
|
||||||
|
module Config
|
||||||
|
class Puppet < Vagrant.plugin("2", :config)
|
||||||
|
attr_accessor :manifest_file
|
||||||
|
attr_accessor :manifests_path
|
||||||
|
attr_accessor :module_path
|
||||||
|
attr_accessor :pp_path
|
||||||
|
attr_accessor :options
|
||||||
|
attr_accessor :facter
|
||||||
|
|
||||||
|
def manifest_file; @manifest_file || "default.pp"; end
|
||||||
|
def manifests_path; @manifests_path || "manifests"; end
|
||||||
|
def pp_path; @pp_path || "/tmp/vagrant-puppet"; end
|
||||||
|
def options; @options ||= []; end
|
||||||
|
def facter; @facter ||= {}; end
|
||||||
|
|
||||||
|
# Returns the manifests path expanded relative to the root path of the
|
||||||
|
# environment.
|
||||||
|
def expanded_manifests_path(root_path)
|
||||||
|
Pathname.new(manifests_path).expand_path(root_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the module paths as an array of paths expanded relative to the
|
||||||
|
# root path.
|
||||||
|
def expanded_module_paths(root_path)
|
||||||
|
return [] if !module_path
|
||||||
|
|
||||||
|
# Get all the paths and expand them relative to the root path, returning
|
||||||
|
# the array of expanded paths
|
||||||
|
paths = module_path
|
||||||
|
paths = [paths] if !paths.is_a?(Array)
|
||||||
|
paths.map do |path|
|
||||||
|
Pathname.new(path).expand_path(root_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate(env, errors)
|
||||||
|
# Calculate the manifests and module paths based on env
|
||||||
|
this_expanded_manifests_path = expanded_manifests_path(env.root_path)
|
||||||
|
this_expanded_module_paths = expanded_module_paths(env.root_path)
|
||||||
|
|
||||||
|
# Manifests path/file validation
|
||||||
|
if !this_expanded_manifests_path.directory?
|
||||||
|
errors.add(I18n.t("vagrant.provisioners.puppet.manifests_path_missing",
|
||||||
|
:path => this_expanded_manifests_path))
|
||||||
|
else
|
||||||
|
expanded_manifest_file = this_expanded_manifests_path.join(manifest_file)
|
||||||
|
if !expanded_manifest_file.file?
|
||||||
|
errors.add(I18n.t("vagrant.provisioners.puppet.manifest_missing",
|
||||||
|
:manifest => expanded_manifest_file.to_s))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Module paths validation
|
||||||
|
this_expanded_module_paths.each do |path|
|
||||||
|
if !path.directory?
|
||||||
|
errors.add(I18n.t("vagrant.provisioners.puppet.module_path_missing", :path => path))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,16 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module Puppet
|
||||||
|
module Config
|
||||||
|
class PuppetServer < Vagrant.plugin("2", :config)
|
||||||
|
attr_accessor :puppet_server
|
||||||
|
attr_accessor :puppet_node
|
||||||
|
attr_accessor :options
|
||||||
|
attr_accessor :facter
|
||||||
|
|
||||||
|
def facter; @facter ||= {}; end
|
||||||
|
def puppet_server; @puppet_server || "puppet"; end
|
||||||
|
def options; @options ||= []; end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -9,12 +9,22 @@ module VagrantPlugins
|
||||||
Puppet either using `puppet apply` or a Puppet server.
|
Puppet either using `puppet apply` or a Puppet server.
|
||||||
DESC
|
DESC
|
||||||
|
|
||||||
provisioner("puppet") do
|
config(:puppet, :provisioner) do
|
||||||
|
require File.expand_path("../config/puppet", __FILE__)
|
||||||
|
Config::Puppet
|
||||||
|
end
|
||||||
|
|
||||||
|
config(:puppet_server, :provisioner) do
|
||||||
|
require File.expand_path("../config/puppet_server", __FILE__)
|
||||||
|
Config::PuppetServer
|
||||||
|
end
|
||||||
|
|
||||||
|
provisioner(:puppet) do
|
||||||
require File.expand_path("../provisioner/puppet", __FILE__)
|
require File.expand_path("../provisioner/puppet", __FILE__)
|
||||||
Provisioner::Puppet
|
Provisioner::Puppet
|
||||||
end
|
end
|
||||||
|
|
||||||
provisioner("puppet_server") do
|
provisioner(:puppet_server) do
|
||||||
require File.expand_path("../provisioner/puppet_server", __FILE__)
|
require File.expand_path("../provisioner/puppet_server", __FILE__)
|
||||||
Provisioner::PuppetServer
|
Provisioner::PuppetServer
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,88 +8,40 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
|
|
||||||
class Puppet < Vagrant.plugin("2", :provisioner)
|
class Puppet < Vagrant.plugin("2", :provisioner)
|
||||||
class Config < Vagrant.plugin("2", :config)
|
def initialize(machine, config)
|
||||||
attr_accessor :manifest_file
|
|
||||||
attr_accessor :manifests_path
|
|
||||||
attr_accessor :module_path
|
|
||||||
attr_accessor :pp_path
|
|
||||||
attr_accessor :options
|
|
||||||
attr_accessor :facter
|
|
||||||
|
|
||||||
def manifest_file; @manifest_file || "default.pp"; end
|
|
||||||
def manifests_path; @manifests_path || "manifests"; end
|
|
||||||
def pp_path; @pp_path || "/tmp/vagrant-puppet"; end
|
|
||||||
def options; @options ||= []; end
|
|
||||||
def facter; @facter ||= {}; end
|
|
||||||
|
|
||||||
# Returns the manifests path expanded relative to the root path of the
|
|
||||||
# environment.
|
|
||||||
def expanded_manifests_path(root_path)
|
|
||||||
Pathname.new(manifests_path).expand_path(root_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the module paths as an array of paths expanded relative to the
|
|
||||||
# root path.
|
|
||||||
def expanded_module_paths(root_path)
|
|
||||||
return [] if !module_path
|
|
||||||
|
|
||||||
# Get all the paths and expand them relative to the root path, returning
|
|
||||||
# the array of expanded paths
|
|
||||||
paths = module_path
|
|
||||||
paths = [paths] if !paths.is_a?(Array)
|
|
||||||
paths.map do |path|
|
|
||||||
Pathname.new(path).expand_path(root_path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def validate(env, errors)
|
|
||||||
# Calculate the manifests and module paths based on env
|
|
||||||
this_expanded_manifests_path = expanded_manifests_path(env.root_path)
|
|
||||||
this_expanded_module_paths = expanded_module_paths(env.root_path)
|
|
||||||
|
|
||||||
# Manifests path/file validation
|
|
||||||
if !this_expanded_manifests_path.directory?
|
|
||||||
errors.add(I18n.t("vagrant.provisioners.puppet.manifests_path_missing",
|
|
||||||
:path => this_expanded_manifests_path))
|
|
||||||
else
|
|
||||||
expanded_manifest_file = this_expanded_manifests_path.join(manifest_file)
|
|
||||||
if !expanded_manifest_file.file?
|
|
||||||
errors.add(I18n.t("vagrant.provisioners.puppet.manifest_missing",
|
|
||||||
:manifest => expanded_manifest_file.to_s))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Module paths validation
|
|
||||||
this_expanded_module_paths.each do |path|
|
|
||||||
if !path.directory?
|
|
||||||
errors.add(I18n.t("vagrant.provisioners.puppet.module_path_missing", :path => path))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.config_class
|
|
||||||
Config
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(env, config)
|
|
||||||
super
|
super
|
||||||
|
|
||||||
@logger = Log4r::Logger.new("vagrant::provisioners::puppet")
|
@logger = Log4r::Logger.new("vagrant::provisioners::puppet")
|
||||||
end
|
end
|
||||||
|
|
||||||
def prepare
|
def configure(root_config)
|
||||||
# Calculate the paths we're going to use based on the environment
|
# Calculate the paths we're going to use based on the environment
|
||||||
@expanded_manifests_path = config.expanded_manifests_path(env[:root_path])
|
root_path = @machine.env.root_path
|
||||||
@expanded_module_paths = config.expanded_module_paths(env[:root_path])
|
@expanded_manifests_path = @config.expanded_manifests_path(root_path)
|
||||||
@manifest_file = File.join(manifests_guest_path, config.manifest_file)
|
@expanded_module_paths = @config.expanded_module_paths(root_path)
|
||||||
|
@manifest_file = File.join(manifests_guest_path, @config.manifest_file)
|
||||||
|
|
||||||
set_module_paths
|
# Setup the module paths
|
||||||
share_manifests
|
@module_paths = []
|
||||||
share_module_paths
|
@expanded_module_paths.each_with_index do |path, i|
|
||||||
|
@module_paths << [path, File.join(config.pp_path, "modules-#{i}")]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Share the manifests directory with the guest
|
||||||
|
root_config.vm.share_folder(
|
||||||
|
"manifests", manifests_guest_path, @expanded_manifests_path)
|
||||||
|
|
||||||
|
# Share the module paths
|
||||||
|
count = 0
|
||||||
|
@module_paths.each do |from, to|
|
||||||
|
# Sorry for the cryptic key here, but VirtualBox has a strange limit on
|
||||||
|
# maximum size for it and its something small (around 10)
|
||||||
|
root_config.vm.share_folder("v-pp-m#{count}", to, from)
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def provision!
|
def provision
|
||||||
# Check that the shared folders are properly shared
|
# Check that the shared folders are properly shared
|
||||||
check = [manifests_guest_path]
|
check = [manifests_guest_path]
|
||||||
@module_paths.each do |host_path, guest_path|
|
@module_paths.each do |host_path, guest_path|
|
||||||
|
@ -103,36 +55,16 @@ module VagrantPlugins
|
||||||
run_puppet_apply
|
run_puppet_apply
|
||||||
end
|
end
|
||||||
|
|
||||||
def share_manifests
|
|
||||||
env[:machine].config.vm.share_folder("manifests", manifests_guest_path, @expanded_manifests_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def share_module_paths
|
|
||||||
count = 0
|
|
||||||
@module_paths.each do |from, to|
|
|
||||||
# Sorry for the cryptic key here, but VirtualBox has a strange limit on
|
|
||||||
# maximum size for it and its something small (around 10)
|
|
||||||
env[:machine].config.vm.share_folder("v-pp-m#{count}", to, from)
|
|
||||||
count += 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_module_paths
|
|
||||||
@module_paths = []
|
|
||||||
@expanded_module_paths.each_with_index do |path, i|
|
|
||||||
@module_paths << [path, File.join(config.pp_path, "modules-#{i}")]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def manifests_guest_path
|
def manifests_guest_path
|
||||||
File.join(config.pp_path, "manifests")
|
File.join(config.pp_path, "manifests")
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify_binary(binary)
|
def verify_binary(binary)
|
||||||
env[:machine].communicate.sudo("which #{binary}",
|
@machine.communicate.sudo(
|
||||||
:error_class => PuppetError,
|
"which #{binary}",
|
||||||
:error_key => :not_detected,
|
:error_class => PuppetError,
|
||||||
:binary => binary)
|
:error_key => :not_detected,
|
||||||
|
:binary => binary)
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_puppet_apply
|
def run_puppet_apply
|
||||||
|
@ -155,19 +87,19 @@ module VagrantPlugins
|
||||||
|
|
||||||
command = "cd #{manifests_guest_path} && #{facter}puppet apply #{options} --detailed-exitcodes || [ $? -eq 2 ]"
|
command = "cd #{manifests_guest_path} && #{facter}puppet apply #{options} --detailed-exitcodes || [ $? -eq 2 ]"
|
||||||
|
|
||||||
env[:ui].info I18n.t("vagrant.provisioners.puppet.running_puppet",
|
@machine.env.ui.info I18n.t("vagrant.provisioners.puppet.running_puppet",
|
||||||
:manifest => @manifest_file)
|
:manifest => @manifest_file)
|
||||||
|
|
||||||
env[:machine].communicate.sudo(command) do |type, data|
|
@machine.communicate.sudo(command) do |type, data|
|
||||||
data.chomp!
|
data.chomp!
|
||||||
env[:ui].info(data, :prefix => false) if !data.empty?
|
@machine.env.ui.info(data, :prefix => false) if !data.empty?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify_shared_folders(folders)
|
def verify_shared_folders(folders)
|
||||||
folders.each do |folder|
|
folders.each do |folder|
|
||||||
@logger.debug("Checking for shared folder: #{folder}")
|
@logger.debug("Checking for shared folder: #{folder}")
|
||||||
if !env[:machine].communicate.test("test -d #{folder}")
|
if !@machine.communicate.test("test -d #{folder}")
|
||||||
raise PuppetError, :missing_shared_folders
|
raise PuppetError, :missing_shared_folders
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,31 +6,17 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
|
|
||||||
class PuppetServer < Vagrant.plugin("2", :provisioner)
|
class PuppetServer < Vagrant.plugin("2", :provisioner)
|
||||||
class Config < Vagrant.plugin("2", :config)
|
def provision
|
||||||
attr_accessor :puppet_server
|
|
||||||
attr_accessor :puppet_node
|
|
||||||
attr_accessor :options
|
|
||||||
attr_accessor :facter
|
|
||||||
|
|
||||||
def facter; @facter ||= {}; end
|
|
||||||
def puppet_server; @puppet_server || "puppet"; end
|
|
||||||
def options; @options ||= []; end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.config_class
|
|
||||||
Config
|
|
||||||
end
|
|
||||||
|
|
||||||
def provision!
|
|
||||||
verify_binary("puppet")
|
verify_binary("puppet")
|
||||||
run_puppet_agent
|
run_puppet_agent
|
||||||
end
|
end
|
||||||
|
|
||||||
def verify_binary(binary)
|
def verify_binary(binary)
|
||||||
env[:vm].channel.sudo("which #{binary}",
|
@machine.communicate.sudo(
|
||||||
:error_class => PuppetServerError,
|
"which #{binary}",
|
||||||
:error_key => :not_detected,
|
:error_class => PuppetServerError,
|
||||||
:binary => binary)
|
:error_key => :not_detected,
|
||||||
|
:binary => binary)
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_puppet_agent
|
def run_puppet_agent
|
||||||
|
@ -43,13 +29,13 @@ module VagrantPlugins
|
||||||
if config.puppet_node
|
if config.puppet_node
|
||||||
# If a node name is given, we use that directly for the certname
|
# If a node name is given, we use that directly for the certname
|
||||||
cn = config.puppet_node
|
cn = config.puppet_node
|
||||||
elsif env[:vm].config.vm.host_name
|
elsif @machine.config.vm.host_name
|
||||||
# If a host name is given, we explicitly set the certname to
|
# If a host name is given, we explicitly set the certname to
|
||||||
# nil so that the hostname becomes the cert name.
|
# nil so that the hostname becomes the cert name.
|
||||||
cn = nil
|
cn = nil
|
||||||
else
|
else
|
||||||
# Otherwise, we default to the name of the box.
|
# Otherwise, we default to the name of the box.
|
||||||
cn = env[:vm].config.vm.box
|
cn = @machine.config.vm.box
|
||||||
end
|
end
|
||||||
|
|
||||||
# Add the certname option if there is one
|
# Add the certname option if there is one
|
||||||
|
@ -69,10 +55,10 @@ module VagrantPlugins
|
||||||
|
|
||||||
command = "#{facter}puppet agent #{options} --server #{config.puppet_server} --detailed-exitcodes || [ $? -eq 2 ]"
|
command = "#{facter}puppet agent #{options} --server #{config.puppet_server} --detailed-exitcodes || [ $? -eq 2 ]"
|
||||||
|
|
||||||
env[:ui].info I18n.t("vagrant.provisioners.puppet_server.running_puppetd")
|
@machine.env.ui.info I18n.t("vagrant.provisioners.puppet_server.running_puppetd")
|
||||||
env[:vm].channel.sudo(command) do |type, data|
|
@machine.communicate.sudo(command) do |type, data|
|
||||||
data.chomp!
|
data.chomp!
|
||||||
env[:ui].info(data, :prefix => false) if !data.empty?
|
@machine.env.ui.info(data, :prefix => false) if !data.empty?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
module VagrantPlugins
|
||||||
|
module Shell
|
||||||
|
class Config < Vagrant.plugin("2", :config)
|
||||||
|
attr_accessor :inline
|
||||||
|
attr_accessor :path
|
||||||
|
attr_accessor :upload_path
|
||||||
|
attr_accessor :args
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@upload_path = "/tmp/vagrant-shell"
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate(env, errors)
|
||||||
|
# Validate that the parameters are properly set
|
||||||
|
if path && inline
|
||||||
|
errors.add(I18n.t("vagrant.provisioners.shell.path_and_inline_set"))
|
||||||
|
elsif !path && !inline
|
||||||
|
errors.add(I18n.t("vagrant.provisioners.shell.no_path_or_inline"))
|
||||||
|
end
|
||||||
|
|
||||||
|
# Validate the existence of a script to upload
|
||||||
|
if path
|
||||||
|
expanded_path = Pathname.new(path).expand_path(env.root_path)
|
||||||
|
if !expanded_path.file?
|
||||||
|
errors.add(I18n.t("vagrant.provisioners.shell.path_invalid",
|
||||||
|
:path => expanded_path))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# There needs to be a path to upload the script to
|
||||||
|
if !upload_path
|
||||||
|
errors.add(I18n.t("vagrant.provisioners.shell.upload_path_not_set"))
|
||||||
|
end
|
||||||
|
|
||||||
|
# If there are args and its not a string, that is a problem
|
||||||
|
if args && !args.is_a?(String)
|
||||||
|
errors.add(I18n.t("vagrant.provisioners.shell.args_not_string"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -9,7 +9,12 @@ module VagrantPlugins
|
||||||
shell scripts.
|
shell scripts.
|
||||||
DESC
|
DESC
|
||||||
|
|
||||||
provisioner("shell") do
|
config(:shell, :provisioner) do
|
||||||
|
require File.expand_path("../config", __FILE__)
|
||||||
|
Config
|
||||||
|
end
|
||||||
|
|
||||||
|
provisioner(:shell) do
|
||||||
require File.expand_path("../provisioner", __FILE__)
|
require File.expand_path("../provisioner", __FILE__)
|
||||||
Provisioner
|
Provisioner
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,48 +4,32 @@ require "tempfile"
|
||||||
module VagrantPlugins
|
module VagrantPlugins
|
||||||
module Shell
|
module Shell
|
||||||
class Provisioner < Vagrant.plugin("2", :provisioner)
|
class Provisioner < Vagrant.plugin("2", :provisioner)
|
||||||
class Config < Vagrant.plugin("2", :config)
|
def provision
|
||||||
attr_accessor :inline
|
args = ""
|
||||||
attr_accessor :path
|
args = " #{config.args}" if config.args
|
||||||
attr_accessor :upload_path
|
command = "chmod +x #{config.upload_path} && #{config.upload_path}#{args}"
|
||||||
attr_accessor :args
|
|
||||||
|
|
||||||
def initialize
|
with_script_file do |path|
|
||||||
@upload_path = "/tmp/vagrant-shell"
|
# Upload the script to the machine
|
||||||
end
|
@machine.communicate.tap do |comm|
|
||||||
|
comm.upload(path.to_s, config.upload_path)
|
||||||
|
|
||||||
def validate(env, errors)
|
# Execute it with sudo
|
||||||
# Validate that the parameters are properly set
|
comm.sudo(command) do |type, data|
|
||||||
if path && inline
|
if [:stderr, :stdout].include?(type)
|
||||||
errors.add(I18n.t("vagrant.provisioners.shell.path_and_inline_set"))
|
# Output the data with the proper color based on the stream.
|
||||||
elsif !path && !inline
|
color = type == :stdout ? :green : :red
|
||||||
errors.add(I18n.t("vagrant.provisioners.shell.no_path_or_inline"))
|
|
||||||
end
|
|
||||||
|
|
||||||
# Validate the existence of a script to upload
|
# Note: Be sure to chomp the data to avoid the newlines that the
|
||||||
if path
|
# Chef outputs.
|
||||||
expanded_path = Pathname.new(path).expand_path(env.root_path)
|
@machine.env.ui.info(data.chomp, :color => color, :prefix => false)
|
||||||
if !expanded_path.file?
|
end
|
||||||
errors.add(I18n.t("vagrant.provisioners.shell.path_invalid",
|
|
||||||
:path => expanded_path))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# There needs to be a path to upload the script to
|
|
||||||
if !upload_path
|
|
||||||
errors.add(I18n.t("vagrant.provisioners.shell.upload_path_not_set"))
|
|
||||||
end
|
|
||||||
|
|
||||||
# If there are args and its not a string, that is a problem
|
|
||||||
if args && !args.is_a?(String)
|
|
||||||
errors.add(I18n.t("vagrant.provisioners.shell.args_not_string"))
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.config_class
|
protected
|
||||||
Config
|
|
||||||
end
|
|
||||||
|
|
||||||
# This method yields the path to a script to upload and execute
|
# This method yields the path to a script to upload and execute
|
||||||
# on the remote server. This method will properly clean up the
|
# on the remote server. This method will properly clean up the
|
||||||
|
@ -53,7 +37,8 @@ module VagrantPlugins
|
||||||
def with_script_file
|
def with_script_file
|
||||||
if config.path
|
if config.path
|
||||||
# Just yield the path to that file...
|
# Just yield the path to that file...
|
||||||
yield Pathname.new(config.path).expand_path(env[:root_path])
|
root_path = @machine.env.root_path
|
||||||
|
yield Pathname.new(config.path).expand_path(root_path)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -75,31 +60,6 @@ module VagrantPlugins
|
||||||
file.unlink
|
file.unlink
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def provision!
|
|
||||||
args = ""
|
|
||||||
args = " #{config.args}" if config.args
|
|
||||||
command = "chmod +x #{config.upload_path} && #{config.upload_path}#{args}"
|
|
||||||
|
|
||||||
with_script_file do |path|
|
|
||||||
# Upload the script to the machine
|
|
||||||
env[:machine].communicate.tap do |comm|
|
|
||||||
comm.upload(path.to_s, config.upload_path)
|
|
||||||
|
|
||||||
# Execute it with sudo
|
|
||||||
comm.sudo(command) do |type, data|
|
|
||||||
if [:stderr, :stdout].include?(type)
|
|
||||||
# Output the data with the proper color based on the stream.
|
|
||||||
color = type == :stdout ? :green : :red
|
|
||||||
|
|
||||||
# Note: Be sure to chomp the data to avoid the newlines that the
|
|
||||||
# Chef outputs.
|
|
||||||
env[:ui].info(data.chomp, :color => color, :prefix => false)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -297,7 +297,7 @@ VF
|
||||||
p.provider(name) { provider_cls }
|
p.provider(name) { provider_cls }
|
||||||
|
|
||||||
if config_class
|
if config_class
|
||||||
p.config(name, :provider => name) { config_class }
|
p.config(name, :provider) { config_class }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
require File.expand_path("../../../../base", __FILE__)
|
require File.expand_path("../../../../base", __FILE__)
|
||||||
|
|
||||||
|
require "vagrant/registry"
|
||||||
|
|
||||||
describe Vagrant::Plugin::V2::Components do
|
describe Vagrant::Plugin::V2::Components do
|
||||||
let(:instance) { described_class.new }
|
let(:instance) { described_class.new }
|
||||||
|
|
||||||
it "should have provider configs" do
|
describe "configs" do
|
||||||
instance.provider_configs.should be_kind_of(Vagrant::Registry)
|
it "should have configs" do
|
||||||
|
instance.configs.should be_kind_of(Hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should default the values to registries" do
|
||||||
|
instance.configs[:i_probably_dont_exist].should be_kind_of(Vagrant::Registry)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,7 +23,7 @@ describe Vagrant::Plugin::V2::Manager do
|
||||||
instance.register(pA)
|
instance.register(pA)
|
||||||
instance.register(pB)
|
instance.register(pB)
|
||||||
|
|
||||||
instance.communicators.length.should == 2
|
instance.communicators.to_hash.length.should == 2
|
||||||
instance.communicators[:foo].should == "bar"
|
instance.communicators[:foo].should == "bar"
|
||||||
instance.communicators[:bar].should == "baz"
|
instance.communicators[:bar].should == "baz"
|
||||||
end
|
end
|
||||||
|
@ -40,7 +40,7 @@ describe Vagrant::Plugin::V2::Manager do
|
||||||
instance.register(pA)
|
instance.register(pA)
|
||||||
instance.register(pB)
|
instance.register(pB)
|
||||||
|
|
||||||
instance.config.length.should == 2
|
instance.config.to_hash.length.should == 2
|
||||||
instance.config[:foo].should == "bar"
|
instance.config[:foo].should == "bar"
|
||||||
instance.config[:bar].should == "baz"
|
instance.config[:bar].should == "baz"
|
||||||
end
|
end
|
||||||
|
@ -57,7 +57,7 @@ describe Vagrant::Plugin::V2::Manager do
|
||||||
instance.register(pA)
|
instance.register(pA)
|
||||||
instance.register(pB)
|
instance.register(pB)
|
||||||
|
|
||||||
instance.guests.length.should == 2
|
instance.guests.to_hash.length.should == 2
|
||||||
instance.guests[:foo].should == "bar"
|
instance.guests[:foo].should == "bar"
|
||||||
instance.guests[:bar].should == "baz"
|
instance.guests[:bar].should == "baz"
|
||||||
end
|
end
|
||||||
|
@ -74,7 +74,7 @@ describe Vagrant::Plugin::V2::Manager do
|
||||||
instance.register(pA)
|
instance.register(pA)
|
||||||
instance.register(pB)
|
instance.register(pB)
|
||||||
|
|
||||||
instance.hosts.length.should == 2
|
instance.hosts.to_hash.length.should == 2
|
||||||
instance.hosts[:foo].should == "bar"
|
instance.hosts[:foo].should == "bar"
|
||||||
instance.hosts[:bar].should == "baz"
|
instance.hosts[:bar].should == "baz"
|
||||||
end
|
end
|
||||||
|
@ -91,25 +91,25 @@ describe Vagrant::Plugin::V2::Manager do
|
||||||
instance.register(pA)
|
instance.register(pA)
|
||||||
instance.register(pB)
|
instance.register(pB)
|
||||||
|
|
||||||
instance.providers.length.should == 2
|
instance.providers.to_hash.length.should == 2
|
||||||
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
|
it "provides the collection of registered provider configs" do
|
||||||
pA = plugin do |p|
|
pA = plugin do |p|
|
||||||
p.config("foo", :provider => true) { "foo" }
|
p.config("foo", :provider) { "foo" }
|
||||||
end
|
end
|
||||||
|
|
||||||
pB = plugin do |p|
|
pB = plugin do |p|
|
||||||
p.config("bar", :provider => true) { "bar" }
|
p.config("bar", :provider) { "bar" }
|
||||||
p.config("baz") { "baz" }
|
p.config("baz") { "baz" }
|
||||||
end
|
end
|
||||||
|
|
||||||
instance.register(pA)
|
instance.register(pA)
|
||||||
instance.register(pB)
|
instance.register(pB)
|
||||||
|
|
||||||
instance.provider_configs.length.should == 2
|
instance.provider_configs.to_hash.length.should == 2
|
||||||
instance.provider_configs[:foo].should == "foo"
|
instance.provider_configs[:foo].should == "foo"
|
||||||
instance.provider_configs[:bar].should == "bar"
|
instance.provider_configs[:bar].should == "bar"
|
||||||
end
|
end
|
||||||
|
|
|
@ -106,7 +106,7 @@ describe Vagrant::Plugin::V2::Plugin do
|
||||||
config("foo") { "bar" }
|
config("foo") { "bar" }
|
||||||
end
|
end
|
||||||
|
|
||||||
plugin.config[:foo].should == "bar"
|
plugin.components.configs[:top][:foo].should == "bar"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should lazily register configuration classes" do
|
it "should lazily register configuration classes" do
|
||||||
|
@ -123,16 +123,16 @@ describe Vagrant::Plugin::V2::Plugin do
|
||||||
# Now verify when we actually get the configuration key that
|
# Now verify when we actually get the configuration key that
|
||||||
# a proper error is raised.
|
# a proper error is raised.
|
||||||
expect {
|
expect {
|
||||||
plugin.config[:foo]
|
plugin.components.configs[:top][:foo]
|
||||||
}.to raise_error(StandardError)
|
}.to raise_error(StandardError)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should register configuration classes for providers" do
|
it "should register configuration classes for providers" do
|
||||||
plugin = Class.new(described_class) do
|
plugin = Class.new(described_class) do
|
||||||
config("foo", :provider => true) { "bar" }
|
config("foo", :provider) { "bar" }
|
||||||
end
|
end
|
||||||
|
|
||||||
plugin.components.provider_configs[:foo].should == "bar"
|
plugin.components.configs[:provider][:foo].should == "bar"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -82,4 +82,47 @@ describe Vagrant::Registry do
|
||||||
result["foo"].should == "foovalue"
|
result["foo"].should == "foovalue"
|
||||||
result["bar"].should == "barvalue"
|
result["bar"].should == "barvalue"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "merging" do
|
||||||
|
it "should merge in another registry" do
|
||||||
|
one = described_class.new
|
||||||
|
two = described_class.new
|
||||||
|
|
||||||
|
one.register("foo") { raise "BOOM!" }
|
||||||
|
two.register("bar") { raise "BAM!" }
|
||||||
|
|
||||||
|
three = one.merge(two)
|
||||||
|
expect { three["foo"] }.to raise_error("BOOM!")
|
||||||
|
expect { three["bar"] }.to raise_error("BAM!")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should NOT merge in the cache" do
|
||||||
|
one = described_class.new
|
||||||
|
two = described_class.new
|
||||||
|
|
||||||
|
one.register("foo") { [] }
|
||||||
|
one["foo"] << 1
|
||||||
|
|
||||||
|
two.register("bar") { [] }
|
||||||
|
two["bar"] << 2
|
||||||
|
|
||||||
|
three = one.merge(two)
|
||||||
|
three["foo"].should == []
|
||||||
|
three["bar"].should == []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "merge!" do
|
||||||
|
it "should merge into self" do
|
||||||
|
one = described_class.new
|
||||||
|
two = described_class.new
|
||||||
|
|
||||||
|
one.register("foo") { "foo" }
|
||||||
|
two.register("bar") { "bar" }
|
||||||
|
|
||||||
|
one.merge!(two)
|
||||||
|
one["foo"].should == "foo"
|
||||||
|
one["bar"].should == "bar"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue