core: provision "once" or "always" [GH-2421]

This commit is contained in:
Mitchell Hashimoto 2014-04-09 15:28:44 -07:00
parent f6fb9016a1
commit aad8e7f80d
8 changed files with 78 additions and 28 deletions

View File

@ -5,6 +5,9 @@ FEATURES:
- Can now specify a `post_up_message` in your Vagrantfile that is shown - Can now specify a `post_up_message` in your Vagrantfile that is shown
after a `vagrant up`. This is useful for putting some instructions of how after a `vagrant up`. This is useful for putting some instructions of how
to use the development environment. to use the development environment.
- Can configure provisioners to run "once" or "always" (defaults to "once"),
so that subsequent `vagrant up` or `reload` calls will always run a
provisioner. [GH-2421]
## 1.5.4 (April 21, 2014) ## 1.5.4 (April 21, 2014)

View File

@ -5,7 +5,7 @@ module Vagrant
# This returns all the instances of the configured provisioners. # This returns all the instances of the configured provisioners.
# This is safe to call multiple times since it will cache the results. # This is safe to call multiple times since it will cache the results.
# #
# @return [Array<Provisioner>] # @return [Array<Provisioner, Hash>]
def provisioner_instances(env) def provisioner_instances(env)
return @_provisioner_instances if @_provisioner_instances return @_provisioner_instances if @_provisioner_instances
@ -21,8 +21,13 @@ module Vagrant
# Store in the type map so that --provision-with works properly # Store in the type map so that --provision-with works properly
@_provisioner_types[result] = provisioner.name @_provisioner_types[result] = provisioner.name
# Build up the options
options = {
run: provisioner.run,
}
# Return the result # Return the result
result [result, options]
end end
return @_provisioner_instances return @_provisioner_instances

View File

@ -22,8 +22,12 @@ module Vagrant
def call(env) def call(env)
@env = env @env = env
# Tracks whether we were configured to provision
config_enabled = true
config_enabled = env[:provision_enabled] if env.has_key?(:provision_enabled)
# Check if we already provisioned, and if so, disable the rest # Check if we already provisioned, and if so, disable the rest
enabled = true sentinel_enabled = true
ignore_sentinel = true ignore_sentinel = true
if env.has_key?(:provision_ignore_sentinel) if env.has_key?(:provision_ignore_sentinel)
@ -52,11 +56,11 @@ module Vagrant
if parts.length == 1 if parts.length == 1
@logger.info("Old-style sentinel found! Not provisioning.") @logger.info("Old-style sentinel found! Not provisioning.")
enabled = false sentinel_enabled = false
update_sentinel = true update_sentinel = true
elsif parts[0] == "1.5" && parts[1] == env[:machine].id.to_s elsif parts[0] == "1.5" && parts[1] == env[:machine].id.to_s
@logger.info("Sentinel found! Not provisioning.") @logger.info("Sentinel found! Not provisioning.")
enabled = false sentinel_enabled = false
else else
@logger.info("Sentinel found with another machine ID. Removing.") @logger.info("Sentinel found with another machine ID. Removing.")
sentinel_path.unlink sentinel_path.unlink
@ -65,10 +69,10 @@ module Vagrant
end end
# Store the value so that other actions can use it # Store the value so that other actions can use it
env[:provision_enabled] = enabled if !env.has_key?(:provision_enabled) env[:provision_enabled] = sentinel_enabled if !env.has_key?(:provision_enabled)
# Ask the provisioners to modify the configuration if needed # Ask the provisioners to modify the configuration if needed
provisioner_instances(env).each do |p| provisioner_instances(env).each do |p, _|
p.configure(env[:machine].config) p.configure(env[:machine].config)
end end
@ -85,27 +89,37 @@ module Vagrant
end end
end end
# Actually provision if we enabled it # If we're configured to not provision, notify the user and stop
if env[:provision_enabled] if !config_enabled
type_map = provisioner_type_map(env) env[:ui].info(I18n.t("vagrant.actions.vm.provision.disabled_by_config"))
provisioner_instances(env).each do |p| return
type_name = type_map[p] end
next if env[:provision_types] && \
!env[:provision_types].include?(type_name)
env[:ui].info(I18n.t( # If we're not provisioning because of the sentinel, tell the user
"vagrant.actions.vm.provision.beginning", # but continue trying for the "always" provisioners
provisioner: type_name)) if !sentinel_enabled
env[:hook].call(:provisioner_run, env.merge(
callable: method(:run_provisioner),
provisioner: p,
provisioner_name: type_name,
))
end
elsif !enabled
env[:ui].info(I18n.t("vagrant.actions.vm.provision.disabled_by_sentinel")) env[:ui].info(I18n.t("vagrant.actions.vm.provision.disabled_by_sentinel"))
end end
type_map = provisioner_type_map(env)
provisioner_instances(env).each do |p, options|
type_name = type_map[p]
next if env[:provision_types] && \
!env[:provision_types].include?(type_name)
# Don't run if sentinel is around and we're not always running
next if !sentinel_enabled && options[:run] != :always
env[:ui].info(I18n.t(
"vagrant.actions.vm.provision.beginning",
provisioner: type_name))
env[:hook].call(:provisioner_run, env.merge(
callable: method(:run_provisioner),
provisioner: p,
provisioner_name: type_name,
))
end
end end
# This is pulled out into a seperate method so that users can # This is pulled out into a seperate method so that users can

View File

@ -30,7 +30,7 @@ module Vagrant
type_map = provisioner_type_map(env) type_map = provisioner_type_map(env)
# Ask the provisioners to modify the configuration if needed # Ask the provisioners to modify the configuration if needed
provisioner_instances(env).each do |p| provisioner_instances(env).each do |p, _|
env[:ui].info(I18n.t( env[:ui].info(I18n.t(
"vagrant.provisioner_cleanup", "vagrant.provisioner_cleanup",
name: type_map[p].to_s)) name: type_map[p].to_s))

View File

@ -126,6 +126,7 @@ module VagrantPlugins
if other_p if other_p
# There is an override. Take it. # There is an override. Take it.
other_p.config = p.config.merge(other_p.config) other_p.config = p.config.merge(other_p.config)
other_p.run ||= p.run
next if !other_p.preserve_order next if !other_p.preserve_order
# We're preserving order, delete from other # We're preserving order, delete from other
@ -269,6 +270,7 @@ module VagrantPlugins
end end
prov.preserve_order = !!options[:preserve_order] prov.preserve_order = !!options[:preserve_order]
prov.run = options.delete(:run) if options.has_key?(:run)
prov.add_config(options, &block) prov.add_config(options, &block)
nil nil
end end
@ -395,6 +397,7 @@ module VagrantPlugins
# Finalize all the provisioners # Finalize all the provisioners
@provisioners.each do |p| @provisioners.each do |p|
p.config.finalize! if !p.invalid? p.config.finalize! if !p.invalid?
p.run = p.run.to_sym if p.run
end end
# If we didn't share our current directory, then do it # If we didn't share our current directory, then do it

View File

@ -20,6 +20,11 @@ module VagrantPlugins
# @return [Object] # @return [Object]
attr_accessor :config attr_accessor :config
# When to run this provisioner. Either "once" or "always"
#
# @return [String]
attr_accessor :run
# Whether or not to preserve the order when merging this with a # Whether or not to preserve the order when merging this with a
# parent scope. # parent scope.
# #
@ -35,6 +40,7 @@ module VagrantPlugins
@invalid = false @invalid = false
@name = name @name = name
@preserve_order = false @preserve_order = false
@run = nil
# Attempt to find the provisioner... # Attempt to find the provisioner...
if !Vagrant.plugin("2").manager.provisioners[name] if !Vagrant.plugin("2").manager.provisioners[name]

View File

@ -1490,8 +1490,11 @@ en:
mounting: Mounting NFS shared folders... mounting: Mounting NFS shared folders...
provision: provision:
beginning: "Running provisioner: %{provisioner}..." beginning: "Running provisioner: %{provisioner}..."
disabled_by_config: |-
Machine not provisioning because `--no-provision` is specified.
disabled_by_sentinel: |- disabled_by_sentinel: |-
VM already provisioned. Run `vagrant provision` or use `--provision` to force it Machine already provisioned. Run `vagrant provision` or use the `--provision`
to force provisioning. Provisioners marked to run always will still run.
resume: resume:
resuming: Resuming suspended VM... resuming: Resuming suspended VM...
unpausing: |- unpausing: |-

View File

@ -214,14 +214,16 @@ describe VagrantPlugins::Kernel_V2::VMConfig do
describe "#provision" do describe "#provision" do
it "stores the provisioners" do it "stores the provisioners" do
subject.provision("shell", inline: "foo") subject.provision("shell", inline: "foo")
subject.provision("shell", inline: "bar") { |s| s.path = "baz" } subject.provision("shell", inline: "bar", run: "always") { |s| s.path = "baz" }
subject.finalize! subject.finalize!
r = subject.provisioners r = subject.provisioners
expect(r.length).to eql(2) expect(r.length).to eql(2)
expect(r[0].run).to be_nil
expect(r[0].config.inline).to eql("foo") expect(r[0].config.inline).to eql("foo")
expect(r[1].config.inline).to eql("bar") expect(r[1].config.inline).to eql("bar")
expect(r[1].config.path).to eql("baz") expect(r[1].config.path).to eql("baz")
expect(r[1].run).to eql(:always)
end end
it "allows provisioner settings to be overriden" do it "allows provisioner settings to be overriden" do
@ -264,6 +266,20 @@ describe VagrantPlugins::Kernel_V2::VMConfig do
end end
describe "merging" do describe "merging" do
it "ignores non-overriding runs" do
subject.provision("shell", inline: "foo", run: "once")
other = described_class.new
other.provision("shell", inline: "bar", run: "always")
merged = subject.merge(other)
merged_provs = merged.provisioners
expect(merged_provs.length).to eql(2)
expect(merged_provs[0].run).to eq("once")
expect(merged_provs[1].run).to eq("always")
end
it "copies the configs" do it "copies the configs" do
subject.provision("shell", inline: "foo") subject.provision("shell", inline: "foo")
subject_provs = subject.provisioners subject_provs = subject.provisioners