Merge pull request #11579 from soapy1/provisioner-communicator_required
Provisioner communicator required
This commit is contained in:
commit
3d4b721a22
@ -25,6 +25,7 @@ module Vagrant
|
||||
autoload :HandleBox, "vagrant/action/builtin/handle_box"
|
||||
autoload :HandleBoxUrl, "vagrant/action/builtin/handle_box_url"
|
||||
autoload :HandleForwardedPortCollisions, "vagrant/action/builtin/handle_forwarded_port_collisions"
|
||||
autoload :HasProvisioner, "vagrant/action/builtin/has_provisioner"
|
||||
autoload :IsEnvSet, "vagrant/action/builtin/is_env_set"
|
||||
autoload :IsState, "vagrant/action/builtin/is_state"
|
||||
autoload :Lock, "vagrant/action/builtin/lock"
|
||||
|
||||
36
lib/vagrant/action/builtin/has_provisioner.rb
Normal file
36
lib/vagrant/action/builtin/has_provisioner.rb
Normal file
@ -0,0 +1,36 @@
|
||||
module Vagrant
|
||||
module Action
|
||||
module Builtin
|
||||
# This middleware is used with Call to test if this machine
|
||||
# has available provisioners
|
||||
class HasProvisioner
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
@logger = Log4r::Logger.new("vagrant::action::builtin::has_provisioner")
|
||||
end
|
||||
|
||||
def call(env)
|
||||
machine = env[:machine]
|
||||
|
||||
if machine.provider.capability?(:has_communicator)
|
||||
has_communicator = machine.provider.capability(:has_communicator)
|
||||
else
|
||||
has_communicator = true
|
||||
end
|
||||
|
||||
env[:skip] = []
|
||||
if !has_communicator
|
||||
machine.config.vm.provisioners.each do |p|
|
||||
if p.communicator_required
|
||||
env[:skip].push(p)
|
||||
@logger.info("Skipping running provisioner #{p.name || 'no name'}, type: #{p.type}")
|
||||
p.run = :never
|
||||
end
|
||||
end
|
||||
end
|
||||
@app.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -49,6 +49,7 @@ module Vagrant
|
||||
run: provisioner.run,
|
||||
before: provisioner.before,
|
||||
after: provisioner.after,
|
||||
communicator_required: provisioner.communicator_required,
|
||||
}
|
||||
|
||||
# Return the result
|
||||
|
||||
@ -410,6 +410,8 @@ module VagrantPlugins
|
||||
prov.preserve_order = !!options.delete(:preserve_order) if \
|
||||
options.key?(:preserve_order)
|
||||
prov.run = options.delete(:run) if options.key?(:run)
|
||||
prov.communicator_required = options.delete(:communicator_required) if options.key?(:communicator_required)
|
||||
|
||||
prov.add_config(options, &block)
|
||||
nil
|
||||
end
|
||||
|
||||
@ -56,6 +56,12 @@ module VagrantPlugins
|
||||
# @return [String, Symbol]
|
||||
attr_accessor :after
|
||||
|
||||
# Boolean, when true signifies that some communicator must
|
||||
# be available in order for the provisioner to run.
|
||||
#
|
||||
# @return [Boolean]
|
||||
attr_accessor :communicator_required
|
||||
|
||||
def initialize(name, type, **options)
|
||||
@logger = Log4r::Logger.new("vagrant::config::vm::provisioner")
|
||||
@logger.debug("Provisioner defined: #{name}")
|
||||
@ -69,6 +75,7 @@ module VagrantPlugins
|
||||
@type = type
|
||||
@before = options[:before]
|
||||
@after = options[:after]
|
||||
@communicator_required = options.fetch(:communicator_required, true)
|
||||
|
||||
# Attempt to find the provisioner...
|
||||
if !Vagrant.plugin("2").manager.provisioners[type]
|
||||
@ -118,6 +125,10 @@ module VagrantPlugins
|
||||
|
||||
provisioner_names = provisioners.map { |i| i.name.to_s if i.name != name }.compact
|
||||
|
||||
if ![TrueClass, FalseClass].include?(@communicator_required.class)
|
||||
errors << I18n.t("vagrant.provisioners.base.wrong_type", opt: "communicator_required", type: "boolean")
|
||||
end
|
||||
|
||||
if @before && @after
|
||||
errors << I18n.t("vagrant.provisioners.base.both_before_after_set")
|
||||
end
|
||||
@ -127,7 +138,7 @@ module VagrantPlugins
|
||||
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")
|
||||
errors << I18n.t("vagrant.provisioners.base.wrong_type", opt: "before", type: "string")
|
||||
end
|
||||
|
||||
if !provisioner_names.include?(@before)
|
||||
@ -153,7 +164,7 @@ module VagrantPlugins
|
||||
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")
|
||||
errors << I18n.t("vagrant.provisioners.base.wrong_type", opt: "after", type: "string")
|
||||
end
|
||||
|
||||
if !provisioner_names.include?(@after)
|
||||
|
||||
@ -66,14 +66,8 @@ module VagrantPlugins
|
||||
next
|
||||
end
|
||||
|
||||
b3.use Call, HasSSH do |env3, b4|
|
||||
if env3[:result]
|
||||
b4.use Provision
|
||||
else
|
||||
b4.use Message,
|
||||
I18n.t("docker_provider.messages.provision_no_ssh"),
|
||||
post: true
|
||||
end
|
||||
b3.use Call, HasProvisioner do |env3, b4|
|
||||
b4.use Provision
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -216,14 +210,8 @@ module VagrantPlugins
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
b.use Call, IsState, :running do |env, b2|
|
||||
if env[:machine_action] != :run_command
|
||||
b2.use Call, HasSSH do |env2, b3|
|
||||
if env2[:result]
|
||||
b3.use Provision
|
||||
else
|
||||
b3.use Message,
|
||||
I18n.t("docker_provider.messages.provision_no_ssh"),
|
||||
post: true
|
||||
end
|
||||
b2.use Call, HasProvisioner do |env2, b3|
|
||||
b3.use Provision
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
11
plugins/providers/docker/cap/has_communicator.rb
Normal file
11
plugins/providers/docker/cap/has_communicator.rb
Normal file
@ -0,0 +1,11 @@
|
||||
module VagrantPlugins
|
||||
module DockerProvider
|
||||
module Cap
|
||||
module HasCommunicator
|
||||
def self.has_communicator(machine)
|
||||
return machine.provider_config.has_ssh
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -67,6 +67,11 @@ module VagrantPlugins
|
||||
Cap::ProxyMachine
|
||||
end
|
||||
|
||||
provider_capability("docker", "has_communicator") do
|
||||
require_relative "cap/has_communicator"
|
||||
Cap::HasCommunicator
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def self.init!
|
||||
|
||||
@ -2697,7 +2697,7 @@ en:
|
||||
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.
|
||||
Provisioner option `%{opt}` is not set as a valid type. Must be a %{type}.
|
||||
chef:
|
||||
chef_not_detected: |-
|
||||
The chef binary (either `chef-solo` or `chef-client`) was not found on
|
||||
|
||||
@ -133,6 +133,10 @@ en:
|
||||
Stopping container...
|
||||
container_ready: |-
|
||||
Container started and ready for use!
|
||||
not_provisioning: |-
|
||||
The following provisioners require a communicator, though none is available (this container does not support SSH).
|
||||
Not running the following provisioners:
|
||||
- %{provisioners}
|
||||
|
||||
status:
|
||||
host_state_unknown: |-
|
||||
|
||||
@ -441,15 +441,18 @@ describe VagrantPlugins::Kernel_V2::VMConfig do
|
||||
it "stores the provisioners" do
|
||||
subject.provision("shell", inline: "foo")
|
||||
subject.provision("shell", inline: "bar", run: "always") { |s| s.path = "baz" }
|
||||
subject.provision("shell", inline: "foo", communicator_required: false)
|
||||
subject.finalize!
|
||||
|
||||
r = subject.provisioners
|
||||
expect(r.length).to eql(2)
|
||||
expect(r.length).to eql(3)
|
||||
expect(r[0].run).to be_nil
|
||||
expect(r[0].config.inline).to eql("foo")
|
||||
expect(r[1].config.inline).to eql("bar")
|
||||
expect(r[1].config.path).to eql("baz")
|
||||
expect(r[1].run).to eql(:always)
|
||||
expect(r[1].communicator_required).to eql(true)
|
||||
expect(r[2].communicator_required).to eql(false)
|
||||
end
|
||||
|
||||
it "allows provisioner settings to be overridden" do
|
||||
|
||||
66
test/unit/vagrant/action/builtin/has_provisioner_test.rb
Normal file
66
test/unit/vagrant/action/builtin/has_provisioner_test.rb
Normal file
@ -0,0 +1,66 @@
|
||||
require File.expand_path("../../../../base", __FILE__)
|
||||
|
||||
|
||||
describe Vagrant::Action::Builtin::HasProvisioner do
|
||||
include_context "unit"
|
||||
|
||||
let(:provisioner_one) { double("provisioner_one") }
|
||||
let(:provisioner_two) { double("provisioner_two") }
|
||||
let(:provisioners) { [provisioner_one, provisioner_two] }
|
||||
let(:machine) { double("machine") }
|
||||
let(:ui) {double("ui") }
|
||||
let(:env) {{ machine: machine, ui: ui, root_path: Pathname.new(".") }}
|
||||
let(:app) { lambda { |*args| }}
|
||||
|
||||
subject { described_class.new(app, env) }
|
||||
|
||||
describe "#call" do
|
||||
before do
|
||||
allow(provisioner_one).to receive(:communicator_required).and_return(true)
|
||||
allow(provisioner_one).to receive(:name)
|
||||
allow(provisioner_one).to receive(:type)
|
||||
allow(provisioner_two).to receive(:communicator_required).and_return(false)
|
||||
allow(provisioner_two).to receive(:name)
|
||||
allow(provisioner_two).to receive(:type)
|
||||
allow(machine).to receive_message_chain(:config, :vm, :provisioners).and_return(provisioners)
|
||||
end
|
||||
|
||||
context "provider has capability :has_communicator" do
|
||||
before do
|
||||
allow(machine).to receive_message_chain(:provider, :capability?).with(:has_communicator).and_return(true)
|
||||
end
|
||||
|
||||
it "does not skip any provisioners if provider has ssh" do
|
||||
allow(machine).to receive_message_chain(:provider, :capability).with(:has_communicator).and_return(true)
|
||||
expect(provisioner_one).to_not receive(:communicator_required)
|
||||
expect(provisioner_two).to_not receive(:communicator_required)
|
||||
|
||||
subject.call(env)
|
||||
expect(env[:skip]).to eq([])
|
||||
end
|
||||
|
||||
it "skips provisioners that require a communicator if provider does not have ssh" do
|
||||
allow(machine).to receive_message_chain(:provider, :capability).with(:has_communicator).and_return(false)
|
||||
expect(provisioner_one).to receive(:communicator_required)
|
||||
expect(provisioner_two).to receive(:communicator_required)
|
||||
expect(provisioner_one).to receive(:run=).with(:never)
|
||||
|
||||
subject.call(env)
|
||||
expect(env[:skip]).to eq([provisioner_one])
|
||||
end
|
||||
end
|
||||
|
||||
context "provider does not have capability :has_communicator" do
|
||||
before do
|
||||
allow(machine).to receive_message_chain(:provider, :capability?).with(:has_communicator).and_return(false)
|
||||
end
|
||||
|
||||
it "does not skip any provisioners" do
|
||||
expect(provisioner_one).to_not receive(:communicator_required)
|
||||
expect(provisioner_two).to_not receive(:communicator_required)
|
||||
subject.call(env)
|
||||
expect(env[:skip]).to eq([])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -35,6 +35,11 @@ option is what type a provisioner is:
|
||||
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).
|
||||
* `communicator_required` (boolean) - Specifies the machine must be accessible by
|
||||
Vagrant in order to run the provisioner. If set to true, the provisioner will
|
||||
only run if Vagrant can establish communication with the guest. If set to false
|
||||
the provisioner will run regardless of Vagrant's ability to communicate with the
|
||||
guest. Defaults to true.
|
||||
|
||||
More information about how to use `before` and `after` options can be read [below](#dependency-provisioners).
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user