provisioners/ansible: Validate compatibility_mode

- Use `'auto'` instead of `nil` for the auto-detection mode
- Add strict validation and related error message
This commit is contained in:
Gilles Cornu 2017-08-26 08:47:35 +02:00
parent e2621a42fc
commit a327e34861
No known key found for this signature in database
GPG Key ID: F6BC2CF7E1FE8FFF
7 changed files with 56 additions and 24 deletions

View File

@ -46,7 +46,7 @@ module VagrantPlugins
def initialize
@become = UNSET_VALUE
@become_user = UNSET_VALUE
@compatibility_mode = UNSET_VALUE
@compatibility_mode = Ansible::COMPATIBILITY_MODE_AUTO
@config_file = UNSET_VALUE
@extra_vars = UNSET_VALUE
@galaxy_role_file = UNSET_VALUE
@ -95,6 +95,12 @@ module VagrantPlugins
def validate(machine)
@errors = _detected_errors
# Validate that a compatibility mode was provided
if !compatibility_mode
@errors << I18n.t("vagrant.provisioners.ansible.errors.no_compatibility_mode",
valid_modes: Ansible::COMPATIBILITY_MODES.map { |s| "'#{s}'" }.join(', '))
end
# Validate that a playbook path was provided
if !playbook
@errors << I18n.t("vagrant.provisioners.ansible.errors.no_playbook")

View File

@ -1,9 +1,14 @@
module VagrantPlugins
module Ansible
COMPATIBILITY_MODE_AUTO = "auto".freeze
COMPATIBILITY_MODE_V1_8 = "1.8".freeze
COMPATIBILITY_MODE_V2_0 = "2.0".freeze
DEFAULT_COMPATIBILITY_MODE = COMPATIBILITY_MODE_V1_8
COMPATIBILITY_MODES = [COMPATIBILITY_MODE_V1_8, COMPATIBILITY_MODE_V2_0].freeze
SAFE_COMPATIBILITY_MODE = COMPATIBILITY_MODE_V1_8
COMPATIBILITY_MODES = [
COMPATIBILITY_MODE_AUTO,
COMPATIBILITY_MODE_V1_8,
COMPATIBILITY_MODE_V2_0,
].freeze
end
end

View File

@ -48,11 +48,11 @@ module VagrantPlugins
end
def set_compatibility_mode
unless config.compatibility_mode
if config.compatibility_mode == Ansible::COMPATIBILITY_MODE_AUTO
detect_compatibility_mode(gather_ansible_version)
end
unless Ansible::COMPATIBILITY_MODES.include?(config.compatibility_mode)
unless Ansible::COMPATIBILITY_MODES.slice(1..-1).include?(config.compatibility_mode)
raise "Programming Error: compatibility_mode must correctly set at this stage!"
end
@ -60,7 +60,7 @@ module VagrantPlugins
end
def detect_compatibility_mode(ansible_version_stdoutput)
if config.compatibility_mode
if config.compatibility_mode != Ansible::COMPATIBILITY_MODE_AUTO
raise "Programming Error: detect_compatibility_mode() shouldn't have been called."
end
@ -86,8 +86,8 @@ module VagrantPlugins
# Nothing to do here, the fallback to default compatibility_mode is done below
end
unless config.compatibility_mode
config.compatibility_mode = Ansible::DEFAULT_COMPATIBILITY_MODE
if config.compatibility_mode == Ansible::COMPATIBILITY_MODE_AUTO
config.compatibility_mode = Ansible::SAFE_COMPATIBILITY_MODE
@machine.env.ui.warn(I18n.t("vagrant.provisioners.ansible.compatibility_mode_not_detected",
compatibility_mode: config.compatibility_mode,

View File

@ -2374,6 +2374,8 @@ en:
`%{config_option}` does not exist on the %{system}: %{path}
extra_vars_invalid: |-
`extra_vars` must be a hash or a path to an existing file. Received: %{value} (as %{type})
no_compatibility_mode: |-
`compatibility_mode` must be correctly set (possible values: %{valid_modes}).
no_playbook: |-
`playbook` file path must be set.
raw_arguments_invalid: |-

View File

@ -5,7 +5,7 @@ shared_examples_for 'options shared by both Ansible provisioners' do
expect(subject.become).to be(false)
expect(subject.become_user).to be_nil
expect(subject.compatibility_mode).to be_nil
expect(subject.compatibility_mode).to eql(VagrantPlugins::Ansible::COMPATIBILITY_MODE_AUTO)
expect(subject.config_file).to be_nil
expect(subject.extra_vars).to be_nil
expect(subject.galaxy_command).to eql("ansible-galaxy install --role-file=%{role_file} --roles-path=%{roles_path} --force")
@ -46,23 +46,37 @@ shared_examples_for 'an Ansible provisioner' do | path_prefix, ansible_setup |
describe "compatibility_mode option" do
%w(1.8 2.0).each do |minimal_version|
it "supports compatibility mode '#{minimal_version}'" do
subject.compatibility_mode = minimal_version
VagrantPlugins::Ansible::COMPATIBILITY_MODES.each do |valid_mode|
it "supports compatibility mode '#{valid_mode}'" do
subject.compatibility_mode = valid_mode
subject.finalize!
result = subject.validate(machine)
expect(subject.compatibility_mode).to eql(minimal_version)
expect(subject.compatibility_mode).to eql(valid_mode)
end
end
it "returns an error if the compatibility mode is not set" do
subject.compatibility_mode = nil
subject.finalize!
result = subject.validate(machine)
expect(result[provisioner_label]).to eql([
I18n.t("vagrant.provisioners.ansible.errors.no_compatibility_mode",
valid_modes: "'auto', '1.8', '2.0'")
])
end
%w(invalid 1.9 2.3).each do |invalid_mode|
it "silently forces the compatibility mode detection for invalid mode '#{invalid_mode}'" do
it "returns an error if the compatibility mode is invalid (e.g. '#{invalid_mode}')" do
subject.compatibility_mode = invalid_mode
subject.finalize!
result = subject.validate(machine)
expect(subject.compatibility_mode).to be_nil
expect(result[provisioner_label]).to eql([
I18n.t("vagrant.provisioners.ansible.errors.no_compatibility_mode",
valid_modes: "'auto', '1.8', '2.0'")
])
end
end
@ -109,6 +123,7 @@ shared_examples_for 'an Ansible provisioner' do | path_prefix, ansible_setup |
end
it "it collects and returns all detected errors" do
subject.compatibility_mode = nil
subject.playbook = nil
subject.extra_vars = ["var1", 3, "var2", 5]
subject.raw_arguments = { arg1: 1, arg2: "foo" }
@ -116,7 +131,10 @@ shared_examples_for 'an Ansible provisioner' do | path_prefix, ansible_setup |
result = subject.validate(machine)
expect(result[provisioner_label].size).to eql(3)
expect(result[provisioner_label].size).to eql(4)
expect(result[provisioner_label]).to include(
I18n.t("vagrant.provisioners.ansible.errors.no_compatibility_mode",
valid_modes: "'auto', '1.8', '2.0'"))
expect(result[provisioner_label]).to include(
I18n.t("vagrant.provisioners.ansible.errors.no_playbook"))
expect(result[provisioner_label]).to include(

View File

@ -305,9 +305,9 @@ VF
"ask_become_pass" => "--ask-sudo-pass"})
end
context "with no compatibility_mode defined" do
context "with compatibility_mode 'auto'" do
before do
config.compatibility_mode = nil
config.compatibility_mode = VagrantPlugins::Ansible::COMPATIBILITY_MODE_AUTO
end
valid_versions = {
@ -348,16 +348,16 @@ VF
allow(subject).to receive(:gather_ansible_version).and_return(unknown_ansible_version)
end
it "applies the default compatibility mode ('#{VagrantPlugins::Ansible::DEFAULT_COMPATIBILITY_MODE}')" do
it "applies the safest compatibility mode ('#{VagrantPlugins::Ansible::SAFE_COMPATIBILITY_MODE}')" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with('ansible-playbook', any_args) { |*args|
expect(config.compatibility_mode).to eq(VagrantPlugins::Ansible::DEFAULT_COMPATIBILITY_MODE)
expect(config.compatibility_mode).to eq(VagrantPlugins::Ansible::SAFE_COMPATIBILITY_MODE)
}.and_return(default_execute_result)
end
it "warns about not being able to detect the best compatibility mode" do
expect(machine.env.ui).to receive(:warn).with(
I18n.t("vagrant.provisioners.ansible.compatibility_mode_not_detected",
compatibility_mode: VagrantPlugins::Ansible::DEFAULT_COMPATIBILITY_MODE,
compatibility_mode: VagrantPlugins::Ansible::SAFE_COMPATIBILITY_MODE,
gathered_version: unknown_ansible_version) +
"\n")
end

View File

@ -29,10 +29,11 @@ Some of these options are for advanced usage only and should not be used unless
Possible values:
- `"1.8"` (Ansible versions prior to 1.8 should mostly work well, but some options might not be supported)
- `"2.0"` (The generated Ansible inventory will be incompatible with Ansible 1.x)
- `"auto"` _(Vagrant will automatically select the optimal compatibilty mode by checking the Ansible version currently available)_
- `"1.8"` _(Ansible versions prior to 1.8 should mostly work well, but some options might not be supported)_
- `"2.0"` _(The generated Ansible inventory will be incompatible with Ansible 1.x)_
By default this option is not set, and Vagrant will try to automatically set the optimal compatibilty mode by checking the Ansible version currently available. Note that Vagrant doesn't validate this option, and any unsupported value (e.g. "2.3") will also lead Vagrant to auto-detect the compatibility mode.
By default this option is set to `"auto"`. If Vagrant is not able to detect any supported Ansible version, it will falls back on the compatibility mode `"1.8"` with a warning.
<div class="alert alert-info">
<strong>Compatibility Note:</strong>