Merge pull request #11043 from briancain/provisioner-enhancements
Introduce new Provisioner options: before and after
This commit is contained in:
commit
f74239bed9
|
@ -29,15 +29,92 @@ module Vagrant
|
||||||
options = {
|
options = {
|
||||||
name: provisioner.name,
|
name: provisioner.name,
|
||||||
run: provisioner.run,
|
run: provisioner.run,
|
||||||
|
before: provisioner.before,
|
||||||
|
after: provisioner.after,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Return the result
|
# Return the result
|
||||||
[result, options]
|
[result, options]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@_provisioner_instances = sort_provisioner_instances(@_provisioner_instances)
|
||||||
return @_provisioner_instances.compact
|
return @_provisioner_instances.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Sorts provisioners based on order specified with before/after options
|
||||||
|
#
|
||||||
|
# @return [Array<Provisioner, Hash>]
|
||||||
|
def sort_provisioner_instances(pvs)
|
||||||
|
final_provs = []
|
||||||
|
root_provs = []
|
||||||
|
# extract root provisioners
|
||||||
|
root_provs = pvs.find_all { |_, o| o[:before].nil? && o[:after].nil? }
|
||||||
|
|
||||||
|
if root_provs.size == pvs.size
|
||||||
|
# no dependencies found
|
||||||
|
return pvs
|
||||||
|
end
|
||||||
|
|
||||||
|
# ensure placeholder variables are Arrays
|
||||||
|
dep_provs = []
|
||||||
|
each_provs = []
|
||||||
|
all_provs = []
|
||||||
|
|
||||||
|
# extract dependency provisioners
|
||||||
|
dep_provs = pvs.find_all { |_, o| o[:before].is_a?(String) || o[:after].is_a?(String) }
|
||||||
|
# extract each provisioners
|
||||||
|
each_provs = pvs.find_all { |_,o| o[:before] == :each || o[:after] == :each }
|
||||||
|
# extract all provisioners
|
||||||
|
all_provs = pvs.find_all { |_,o| o[:before] == :all || o[:after] == :all }
|
||||||
|
|
||||||
|
# insert provisioners in order
|
||||||
|
final_provs = root_provs
|
||||||
|
dep_provs.each do |p,options|
|
||||||
|
idx = 0
|
||||||
|
if options[:before]
|
||||||
|
idx = final_provs.index { |_, o| o[:name].to_s == options[:before] }
|
||||||
|
final_provs.insert(idx, [p, options])
|
||||||
|
elsif options[:after]
|
||||||
|
idx = final_provs.index { |_, o| o[:name].to_s == options[:after] }
|
||||||
|
idx += 1
|
||||||
|
final_provs.insert(idx, [p, options])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add :each and :all provisioners in reverse to preserve order in Vagrantfile
|
||||||
|
tmp_final_provs = []
|
||||||
|
final_provs.each_with_index do |(prv,o), i|
|
||||||
|
tmp_before = []
|
||||||
|
tmp_after = []
|
||||||
|
|
||||||
|
each_provs.reverse_each do |p, options|
|
||||||
|
if options[:before]
|
||||||
|
tmp_before << [p,options]
|
||||||
|
elsif options[:after]
|
||||||
|
tmp_after << [p,options]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tmp_final_provs += tmp_before unless tmp_before.empty?
|
||||||
|
tmp_final_provs += [[prv,o]]
|
||||||
|
tmp_final_provs += tmp_after unless tmp_after.empty?
|
||||||
|
end
|
||||||
|
final_provs = tmp_final_provs
|
||||||
|
|
||||||
|
# Add all to final array
|
||||||
|
all_provs.reverse_each do |p,options|
|
||||||
|
if options[:before]
|
||||||
|
final_provs.insert(0, [p,options])
|
||||||
|
elsif options[:after]
|
||||||
|
final_provs.push([p,options])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return final_provs
|
||||||
|
end
|
||||||
|
|
||||||
# This will return a mapping of a provisioner instance to its
|
# This will return a mapping of a provisioner instance to its
|
||||||
# type.
|
# type.
|
||||||
def provisioner_type_map(env)
|
def provisioner_type_map(env)
|
||||||
|
@ -47,6 +124,13 @@ module Vagrant
|
||||||
# Return the type map
|
# Return the type map
|
||||||
@_provisioner_types
|
@_provisioner_types
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @private
|
||||||
|
# Reset the cached values for platform. This is not considered a public
|
||||||
|
# API and should only be used for testing.
|
||||||
|
def self.reset!
|
||||||
|
instance_variables.each(&method(:remove_instance_variable))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,7 @@ require "vagrant/action/builtin/mixin_synced_folders"
|
||||||
require "vagrant/config/v2/util"
|
require "vagrant/config/v2/util"
|
||||||
require "vagrant/util/platform"
|
require "vagrant/util/platform"
|
||||||
require "vagrant/util/presence"
|
require "vagrant/util/presence"
|
||||||
|
require "vagrant/util/experimental"
|
||||||
|
|
||||||
require File.expand_path("../vm_provisioner", __FILE__)
|
require File.expand_path("../vm_provisioner", __FILE__)
|
||||||
require File.expand_path("../vm_subvm", __FILE__)
|
require File.expand_path("../vm_subvm", __FILE__)
|
||||||
|
@ -331,7 +332,19 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
|
|
||||||
if !prov
|
if !prov
|
||||||
|
if options.key?(:before)
|
||||||
|
before = options.delete(:before)
|
||||||
|
end
|
||||||
|
if options.key?(:after)
|
||||||
|
after = options.delete(:after)
|
||||||
|
end
|
||||||
|
|
||||||
|
if Vagrant::Util::Experimental.feature_enabled?("dependency_provisioners")
|
||||||
|
opts = {before: before, after: after}
|
||||||
|
prov = VagrantConfigProvisioner.new(name, type.to_sym, opts)
|
||||||
|
else
|
||||||
prov = VagrantConfigProvisioner.new(name, type.to_sym)
|
prov = VagrantConfigProvisioner.new(name, type.to_sym)
|
||||||
|
end
|
||||||
@provisioners << prov
|
@provisioners << prov
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -760,6 +773,11 @@ module VagrantPlugins
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
|
provisioner_errors = vm_provisioner.validate(machine, @provisioners)
|
||||||
|
if provisioner_errors
|
||||||
|
errors = Vagrant::Config::V2::Util.merge_errors(errors, provisioner_errors)
|
||||||
|
end
|
||||||
|
|
||||||
if vm_provisioner.config
|
if vm_provisioner.config
|
||||||
provisioner_errors = vm_provisioner.config.validate(machine)
|
provisioner_errors = vm_provisioner.config.validate(machine)
|
||||||
if provisioner_errors
|
if provisioner_errors
|
||||||
|
|
|
@ -3,7 +3,10 @@ require 'log4r'
|
||||||
module VagrantPlugins
|
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 < Vagrant.plugin("2", :config)
|
||||||
|
# Defaults
|
||||||
|
VALID_BEFORE_AFTER_TYPES = [:each, :all].freeze
|
||||||
|
|
||||||
# Unique name for this provisioner
|
# Unique name for this provisioner
|
||||||
#
|
#
|
||||||
# @return [String]
|
# @return [String]
|
||||||
|
@ -29,7 +32,7 @@ module VagrantPlugins
|
||||||
# @return [Object]
|
# @return [Object]
|
||||||
attr_accessor :config
|
attr_accessor :config
|
||||||
|
|
||||||
# When to run this provisioner. Either "once" or "always"
|
# When to run this provisioner. Either "once", "always", or "never"
|
||||||
#
|
#
|
||||||
# @return [String]
|
# @return [String]
|
||||||
attr_accessor :run
|
attr_accessor :run
|
||||||
|
@ -40,7 +43,17 @@ module VagrantPlugins
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
attr_accessor :preserve_order
|
attr_accessor :preserve_order
|
||||||
|
|
||||||
def initialize(name, type)
|
# The name of a provisioner to run before it has started
|
||||||
|
#
|
||||||
|
# @return [String, Symbol]
|
||||||
|
attr_accessor :before
|
||||||
|
|
||||||
|
# The name of a provisioner to run after it is finished
|
||||||
|
#
|
||||||
|
# @return [String, Symbol]
|
||||||
|
attr_accessor :after
|
||||||
|
|
||||||
|
def initialize(name, type, **options)
|
||||||
@logger = Log4r::Logger.new("vagrant::config::vm::provisioner")
|
@logger = Log4r::Logger.new("vagrant::config::vm::provisioner")
|
||||||
@logger.debug("Provisioner defined: #{name}")
|
@logger.debug("Provisioner defined: #{name}")
|
||||||
|
|
||||||
|
@ -51,6 +64,8 @@ module VagrantPlugins
|
||||||
@preserve_order = false
|
@preserve_order = false
|
||||||
@run = nil
|
@run = nil
|
||||||
@type = type
|
@type = type
|
||||||
|
@before = options[:before]
|
||||||
|
@after = options[:after]
|
||||||
|
|
||||||
# Attempt to find the provisioner...
|
# Attempt to find the provisioner...
|
||||||
if !Vagrant.plugin("2").manager.provisioners[type]
|
if !Vagrant.plugin("2").manager.provisioners[type]
|
||||||
|
@ -90,6 +105,75 @@ module VagrantPlugins
|
||||||
@config.finalize!
|
@config.finalize!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Validates the before/after options
|
||||||
|
#
|
||||||
|
# @param [Vagrant::Machine] machine - machine to validate against
|
||||||
|
# @param [Array] provisioners - Array of defined provisioners for the guest machine
|
||||||
|
# @return [Array] array of strings of error messages from config option validation
|
||||||
|
def validate(machine, provisioners)
|
||||||
|
errors = _detected_errors
|
||||||
|
|
||||||
|
provisioner_names = provisioners.map { |i| i.name.to_s if i.name != name }.compact
|
||||||
|
|
||||||
|
if @before && @after
|
||||||
|
errors << I18n.t("vagrant.provisioners.base.both_before_after_set")
|
||||||
|
end
|
||||||
|
|
||||||
|
if @before
|
||||||
|
if !VALID_BEFORE_AFTER_TYPES.include?(@before)
|
||||||
|
if @before.is_a?(Symbol) && !VALID_BEFORE_AFTER_TYPES.include?(@before)
|
||||||
|
errors << I18n.t("vagrant.provisioners.base.invalid_alias_value", opt: "before", alias: VALID_BEFORE_AFTER_TYPES.join(", "))
|
||||||
|
elsif !@before.is_a?(String) && !VALID_BEFORE_AFTER_TYPES.include?(@before)
|
||||||
|
errors << I18n.t("vagrant.provisioners.base.wrong_type", opt: "before")
|
||||||
|
end
|
||||||
|
|
||||||
|
if !provisioner_names.include?(@before)
|
||||||
|
errors << I18n.t("vagrant.provisioners.base.missing_provisioner_name",
|
||||||
|
name: @before,
|
||||||
|
machine_name: machine.name,
|
||||||
|
action: "before",
|
||||||
|
provisioner_name: @name)
|
||||||
|
end
|
||||||
|
|
||||||
|
dep_prov = provisioners.find_all { |i| i.name.to_s == @before && (i.before || i.after) }
|
||||||
|
|
||||||
|
if !dep_prov.empty?
|
||||||
|
errors << I18n.t("vagrant.provisioners.base.dependency_provisioner_dependency",
|
||||||
|
name: @name,
|
||||||
|
dep_name: dep_prov.first.name.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if @after
|
||||||
|
if !VALID_BEFORE_AFTER_TYPES.include?(@after)
|
||||||
|
if @after.is_a?(Symbol)
|
||||||
|
errors << I18n.t("vagrant.provisioners.base.invalid_alias_value", opt: "after", alias: VALID_BEFORE_AFTER_TYPES.join(", "))
|
||||||
|
elsif !@after.is_a?(String)
|
||||||
|
errors << I18n.t("vagrant.provisioners.base.wrong_type", opt: "after")
|
||||||
|
end
|
||||||
|
|
||||||
|
if !provisioner_names.include?(@after)
|
||||||
|
errors << I18n.t("vagrant.provisioners.base.missing_provisioner_name",
|
||||||
|
name: @after,
|
||||||
|
machine_name: machine.name,
|
||||||
|
action: "after",
|
||||||
|
provisioner_name: @name)
|
||||||
|
end
|
||||||
|
|
||||||
|
dep_prov = provisioners.find_all { |i| i.name.to_s == @after && (i.before || i.after) }
|
||||||
|
|
||||||
|
if !dep_prov.empty?
|
||||||
|
errors << I18n.t("vagrant.provisioners.base.dependency_provisioner_dependency",
|
||||||
|
name: @name,
|
||||||
|
dep_name: dep_prov.first.name.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
{"provisioner" => errors}
|
||||||
|
end
|
||||||
|
|
||||||
# Returns whether the provisioner used was invalid or not. A provisioner
|
# Returns whether the provisioner used was invalid or not. A provisioner
|
||||||
# is invalid if it can't be found.
|
# is invalid if it can't be found.
|
||||||
#
|
#
|
||||||
|
|
|
@ -2486,6 +2486,17 @@ en:
|
||||||
VirtualBox has successfully been installed!
|
VirtualBox has successfully been installed!
|
||||||
|
|
||||||
provisioners:
|
provisioners:
|
||||||
|
base:
|
||||||
|
both_before_after_set: |-
|
||||||
|
Dependency provisioners cannot currently set both `before` and `after` options.
|
||||||
|
dependency_provisioner_dependency: |-
|
||||||
|
Dependency provisioner "%{name}" relies on another dependency provisioner "%{dep_name}". This is currently not supported.
|
||||||
|
invalid_alias_value: |-
|
||||||
|
Provisioner option `%{opt}` is not set as a valid type. Must be a string, or one of the alias shortcuts: %{alias}
|
||||||
|
missing_provisioner_name: |-
|
||||||
|
Could not find provisioner name `%{name}` defined for machine `%{machine_name}` to run provisioner "%{provisioner_name}" `%{action}`.
|
||||||
|
wrong_type: |-
|
||||||
|
Provisioner option `%{opt}` is not set as a valid type. Must be a string.
|
||||||
chef:
|
chef:
|
||||||
chef_not_detected: |-
|
chef_not_detected: |-
|
||||||
The chef binary (either `chef-solo` or `chef-client`) was not found on
|
The chef binary (either `chef-solo` or `chef-client`) was not found on
|
||||||
|
|
|
@ -0,0 +1,238 @@
|
||||||
|
require File.expand_path("../../../../base", __FILE__)
|
||||||
|
require Vagrant.source_root.join("plugins/kernel_v2/config/vm")
|
||||||
|
|
||||||
|
require "vagrant/action/builtin/mixin_provisioners"
|
||||||
|
|
||||||
|
describe Vagrant::Action::Builtin::MixinProvisioners do
|
||||||
|
include_context "unit"
|
||||||
|
|
||||||
|
let(:sandbox) { isolated_environment }
|
||||||
|
let(:iso_env) do
|
||||||
|
# We have to create a Vagrantfile so there is a root path
|
||||||
|
sandbox.vagrantfile("")
|
||||||
|
sandbox.create_vagrant_env
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:provisioner_config){ {} }
|
||||||
|
let(:provisioner_one) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("spec-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
let(:provisioner_two) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("spec-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:provisioner_instances) { [provisioner_one,provisioner_two] }
|
||||||
|
|
||||||
|
let(:ui) { double("ui") }
|
||||||
|
let(:vm) { double("vm", provisioners: provisioner_instances) }
|
||||||
|
let(:config) { double("config", vm: vm) }
|
||||||
|
let(:machine) { double("machine", ui: ui, config: config) }
|
||||||
|
|
||||||
|
let(:env) {{ machine: machine, ui: machine.ui, root_path: Pathname.new(".") }}
|
||||||
|
|
||||||
|
subject do
|
||||||
|
Class.new do
|
||||||
|
extend Vagrant::Action::Builtin::MixinProvisioners
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
sandbox.close
|
||||||
|
described_class.reset!
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "#provisioner_instances" do
|
||||||
|
it "returns all the instances of configured provisioners" do
|
||||||
|
result = subject.provisioner_instances(env)
|
||||||
|
expect(result.size).to eq(provisioner_instances.size)
|
||||||
|
shell_one = result.first
|
||||||
|
expect(shell_one.first).to be_a(VagrantPlugins::Shell::Provisioner)
|
||||||
|
shell_two = result[1]
|
||||||
|
expect(shell_two.first).to be_a(VagrantPlugins::Shell::Provisioner)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "#sort_provisioner_instances" do
|
||||||
|
describe "with no dependency provisioners" do
|
||||||
|
it "returns the original array" do
|
||||||
|
result = subject.provisioner_instances(env)
|
||||||
|
expect(result.size).to eq(provisioner_instances.size)
|
||||||
|
shell_one = result.first
|
||||||
|
expect(shell_one.first).to be_a(VagrantPlugins::Shell::Provisioner)
|
||||||
|
shell_two = result[1]
|
||||||
|
expect(shell_two.first).to be_a(VagrantPlugins::Shell::Provisioner)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "with before and after dependency provisioners" do
|
||||||
|
let(:provisioner_config){ {} }
|
||||||
|
let(:provisioner_root) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("root-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
let(:provisioner_before) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("before-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov.before = "root-test"
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
let(:provisioner_after) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("after-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov.after = "root-test"
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
let(:provisioner_instances) { [provisioner_root,provisioner_before,provisioner_after] }
|
||||||
|
|
||||||
|
it "returns the array in the correct order" do
|
||||||
|
result = subject.provisioner_instances(env)
|
||||||
|
expect(result[0].last[:name]).to eq("before-test")
|
||||||
|
expect(result[1].last[:name]).to eq("root-test")
|
||||||
|
expect(result[2].last[:name]).to eq("after-test")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "with before :each dependency provisioners" do
|
||||||
|
let(:provisioner_config){ {} }
|
||||||
|
let(:provisioner_root) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("root-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
let(:provisioner_root2) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("root2-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
let(:provisioner_before) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("before-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov.before = :each
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:provisioner_instances) { [provisioner_root,provisioner_root2,provisioner_before] }
|
||||||
|
|
||||||
|
it "puts the each shortcut provisioners in place" do
|
||||||
|
result = subject.provisioner_instances(env)
|
||||||
|
|
||||||
|
expect(result[0].last[:name]).to eq("before-test")
|
||||||
|
expect(result[1].last[:name]).to eq("root-test")
|
||||||
|
expect(result[2].last[:name]).to eq("before-test")
|
||||||
|
expect(result[3].last[:name]).to eq("root2-test")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "with after :each dependency provisioners" do
|
||||||
|
let(:provisioner_config){ {} }
|
||||||
|
let(:provisioner_root) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("root-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
let(:provisioner_root2) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("root2-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
let(:provisioner_after) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("after-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov.after = :each
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:provisioner_instances) { [provisioner_root,provisioner_root2,provisioner_after] }
|
||||||
|
|
||||||
|
it "puts the each shortcut provisioners in place" do
|
||||||
|
result = subject.provisioner_instances(env)
|
||||||
|
|
||||||
|
expect(result[0].last[:name]).to eq("root-test")
|
||||||
|
expect(result[1].last[:name]).to eq("after-test")
|
||||||
|
expect(result[2].last[:name]).to eq("root2-test")
|
||||||
|
expect(result[3].last[:name]).to eq("after-test")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "with before and after :each dependency provisioners" do
|
||||||
|
let(:provisioner_config){ {} }
|
||||||
|
let(:provisioner_root) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("root-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
let(:provisioner_root2) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("root2-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
let(:provisioner_after) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("after-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov.after = :each
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
let(:provisioner_before) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("before-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov.before = :each
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:provisioner_instances) { [provisioner_root,provisioner_root2,provisioner_before,provisioner_after] }
|
||||||
|
|
||||||
|
it "puts the each shortcut provisioners in place" do
|
||||||
|
result = subject.provisioner_instances(env)
|
||||||
|
|
||||||
|
expect(result[0].last[:name]).to eq("before-test")
|
||||||
|
expect(result[1].last[:name]).to eq("root-test")
|
||||||
|
expect(result[2].last[:name]).to eq("after-test")
|
||||||
|
expect(result[3].last[:name]).to eq("before-test")
|
||||||
|
expect(result[4].last[:name]).to eq("root2-test")
|
||||||
|
expect(result[5].last[:name]).to eq("after-test")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "with before and after :all dependency provisioners" do
|
||||||
|
let(:provisioner_config){ {} }
|
||||||
|
let(:provisioner_root) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("root-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
let(:provisioner_root2) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("root2-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
let(:provisioner_after) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("after-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov.after = :all
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
let(:provisioner_before) do
|
||||||
|
prov = VagrantPlugins::Kernel_V2::VagrantConfigProvisioner.new("before-test", :shell)
|
||||||
|
prov.config = provisioner_config
|
||||||
|
prov.before = :all
|
||||||
|
prov
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:provisioner_instances) { [provisioner_root,provisioner_root2,provisioner_before,provisioner_after] }
|
||||||
|
|
||||||
|
it "puts the each shortcut provisioners in place" do
|
||||||
|
result = subject.provisioner_instances(env)
|
||||||
|
|
||||||
|
expect(result[0].last[:name]).to eq("before-test")
|
||||||
|
expect(result[1].last[:name]).to eq("root-test")
|
||||||
|
expect(result[2].last[:name]).to eq("root2-test")
|
||||||
|
expect(result[3].last[:name]).to eq("after-test")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -47,3 +47,10 @@ This is a list of all the valid experimental features that Vagrant recognizes:
|
||||||
|
|
||||||
Enabling this feature allows triggers to recognize and execute `:type` triggers.
|
Enabling this feature allows triggers to recognize and execute `:type` triggers.
|
||||||
More information about how these should be used can be found on the [trigger documentation page](/docs/triggers/configuration.html#trigger-types)
|
More information about how these should be used can be found on the [trigger documentation page](/docs/triggers/configuration.html#trigger-types)
|
||||||
|
|
||||||
|
### `dependency_provisioners`
|
||||||
|
|
||||||
|
Enabling this feature allows all provisioners to specify `before` and `after`
|
||||||
|
options. These options allow provisioners to be configured to run before or after
|
||||||
|
any given "root" provisioner. more information about these options can be found
|
||||||
|
on the [base provisioner documentation page](/docs/provisioning/basic_usage.html)
|
||||||
|
|
|
@ -14,6 +14,31 @@ While Vagrant offers multiple options for how you are able to provision
|
||||||
your machine, there is a standard usage pattern as well as some important
|
your machine, there is a standard usage pattern as well as some important
|
||||||
points common to all provisioners that are important to know.
|
points common to all provisioners that are important to know.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
Every Vagrant provisioner accepts a few base options. The only required
|
||||||
|
option is what type a provisioner is:
|
||||||
|
|
||||||
|
|
||||||
|
* `name` (string) - The name of the provisioner. Note: if no `type` option is given,
|
||||||
|
this option _must_ be the type of provisioner it is. If you wish to give it a
|
||||||
|
different name you must also set the `type` option to define the kind of provisioner.
|
||||||
|
* `type` (string) - The class of provisioner to configure. (i.e. `"shell"` or `"file"`)
|
||||||
|
* `before` (string or symbol) - The exact name of an already defined provisioner
|
||||||
|
that _this_ provisioner should run before. If defined as a symbol, its only valid
|
||||||
|
values are `:each` or `:all`, which makes the provisioner run before each and
|
||||||
|
every root provisioner, or before all provisioners respectively.
|
||||||
|
__Note__: This option is currently experimental, so it needs to be explicitly
|
||||||
|
enabled to work. More info can be found [here](/docs/experimental/index.html).
|
||||||
|
* `after` (string or symbol) - The exact name of an already defined provisioner
|
||||||
|
that _this_ provisioner should run after. If defined as a symbol, its only valid
|
||||||
|
values are `:each` or `:all`, which makes the provisioner run after each and
|
||||||
|
every root provisioner, or before all provisioners respectively.
|
||||||
|
__Note__: This option is currently experimental, so it needs to be explicitly
|
||||||
|
enabled to work. More info can be found [here](/docs/experimental/index.html).
|
||||||
|
|
||||||
|
More information about how to use `before` and `after` options can be read [below](#dependency-provisioners).
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
First, every provisioner is configured within your
|
First, every provisioner is configured within your
|
||||||
|
@ -226,3 +251,118 @@ Vagrant.configure("2") do |config|
|
||||||
inline: "echo SECOND!"
|
inline: "echo SECOND!"
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Dependency Provisioners
|
||||||
|
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<strong>Warning: Advanced Topic!</strong> Dependency provisioners are
|
||||||
|
an advanced topic. If you are just getting started with Vagrant, you can
|
||||||
|
safely skip this.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<strong>Warning!</strong> This feature is still experimental and may break or
|
||||||
|
change in between releases. Use at your own risk.
|
||||||
|
|
||||||
|
This feature currently reqiures the experimental flag to be used. To explicitly enable this feature, you can set the experimental flag to:
|
||||||
|
|
||||||
|
```
|
||||||
|
VAGRANT_EXPERIMENTAL="dependency_provisioners"
|
||||||
|
```
|
||||||
|
|
||||||
|
Please note that `VAGRANT_EXPERIMENTAL` is an environment variable. For more
|
||||||
|
information about this flag visit the [Experimental docs page](/docs/experimental/)
|
||||||
|
for more info. Without this flag enabled, provisioners with the `before` and
|
||||||
|
`after` option will be ignored.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
If a provisioner has been configured using the `before` or `after` options, it
|
||||||
|
is considered a _Dependency Provisioner_. This means it has been configured to
|
||||||
|
run before or after a _Root Provisioner_, which does not have the `before` or
|
||||||
|
`after` options configured.
|
||||||
|
|
||||||
|
Dependency provisioners also have two valid shortcuts:
|
||||||
|
`:each` and `:all`.
|
||||||
|
|
||||||
|
**Note**: As of 2.2.6, dependency provisioners cannot rely on other dependency
|
||||||
|
provisioners and is considered a configuration state error in Vagrant. If you must
|
||||||
|
order dependency provisioners, you can still order them by the order they are defined
|
||||||
|
inside your Vagrantfile.
|
||||||
|
|
||||||
|
An example of these dependency provisioners can be seen below:
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.vm.provision "C", after: "B", type: "shell", inline:<<-SHELL
|
||||||
|
echo 'C'
|
||||||
|
SHELL
|
||||||
|
config.vm.provision "B", type: "shell", inline:<<-SHELL
|
||||||
|
echo 'B'
|
||||||
|
SHELL
|
||||||
|
config.vm.provision "D", type: "shell", inline:<<-SHELL
|
||||||
|
echo 'D'
|
||||||
|
SHELL
|
||||||
|
config.vm.provision "A", before: "B", type: "shell", inline:<<-SHELL
|
||||||
|
echo 'A'
|
||||||
|
SHELL
|
||||||
|
config.vm.provision "Separate After", after: :each, type: "shell", inline:<<-SHELL
|
||||||
|
echo '=============================='
|
||||||
|
SHELL
|
||||||
|
config.vm.provision "Separate Before", before: :each, type: "shell", inline:<<-SHELL
|
||||||
|
echo '++++++++++++++++++++++++++++++'
|
||||||
|
SHELL
|
||||||
|
config.vm.provision "Hello", before: :all, type: "shell", inline:<<-SHELL
|
||||||
|
echo 'HERE WE GO!!'
|
||||||
|
SHELL
|
||||||
|
config.vm.provision "Goodbye", after: :all, type: "shell", inline:<<-SHELL
|
||||||
|
echo 'The end'
|
||||||
|
SHELL
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
The result of running `vagrant provision` with a guest configured above:
|
||||||
|
|
||||||
|
```
|
||||||
|
==> default: Running provisioner: Hello (shell)...
|
||||||
|
default: Running: inline script
|
||||||
|
default: HERE WE GO!!
|
||||||
|
==> default: Running provisioner: Separate Before (shell)...
|
||||||
|
default: Running: inline script
|
||||||
|
default: ++++++++++++++++++++++++++++++
|
||||||
|
==> default: Running provisioner: A (shell)...
|
||||||
|
default: Running: inline script
|
||||||
|
default: A
|
||||||
|
==> default: Running provisioner: Separate After (shell)...
|
||||||
|
default: Running: inline script
|
||||||
|
default: ==============================
|
||||||
|
==> default: Running provisioner: Separate Before (shell)...
|
||||||
|
default: Running: inline script
|
||||||
|
default: ++++++++++++++++++++++++++++++
|
||||||
|
==> default: Running provisioner: B (shell)...
|
||||||
|
default: Running: inline script
|
||||||
|
default: B
|
||||||
|
==> default: Running provisioner: Separate After (shell)...
|
||||||
|
default: Running: inline script
|
||||||
|
default: ==============================
|
||||||
|
==> default: Running provisioner: Separate Before (shell)...
|
||||||
|
default: Running: inline script
|
||||||
|
default: ++++++++++++++++++++++++++++++
|
||||||
|
==> default: Running provisioner: C (shell)...
|
||||||
|
default: Running: inline script
|
||||||
|
default: C
|
||||||
|
==> default: Running provisioner: Separate After (shell)...
|
||||||
|
default: Running: inline script
|
||||||
|
default: ==============================
|
||||||
|
==> default: Running provisioner: Separate Before (shell)...
|
||||||
|
default: Running: inline script
|
||||||
|
default: ++++++++++++++++++++++++++++++
|
||||||
|
==> default: Running provisioner: D (shell)...
|
||||||
|
default: Running: inline script
|
||||||
|
default: D
|
||||||
|
==> default: Running provisioner: Separate After (shell)...
|
||||||
|
default: Running: inline script
|
||||||
|
default: ==============================
|
||||||
|
==> default: Running provisioner: Goodbye (shell)...
|
||||||
|
default: Running: inline script
|
||||||
|
default: The end
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in New Issue