diff --git a/plugins/provisioners/ansible/config/base.rb b/plugins/provisioners/ansible/config/base.rb index 22693122c..201554bdf 100644 --- a/plugins/provisioners/ansible/config/base.rb +++ b/plugins/provisioners/ansible/config/base.rb @@ -28,6 +28,7 @@ module VagrantPlugins attr_accessor :tags attr_accessor :vault_password_file attr_accessor :verbose + attr_accessor :version # # Deprecated options @@ -64,6 +65,7 @@ module VagrantPlugins @tags = UNSET_VALUE @vault_password_file = UNSET_VALUE @verbose = UNSET_VALUE + @version = UNSET_VALUE end def finalize! @@ -87,6 +89,7 @@ module VagrantPlugins @tags = nil if @tags == UNSET_VALUE @vault_password_file = nil if @vault_password_file == UNSET_VALUE @verbose = false if @verbose == UNSET_VALUE + @version = "" if @version == UNSET_VALUE end # Just like the normal configuration "validate" method except that diff --git a/plugins/provisioners/ansible/config/guest.rb b/plugins/provisioners/ansible/config/guest.rb index 16992cb5a..a869779ae 100644 --- a/plugins/provisioners/ansible/config/guest.rb +++ b/plugins/provisioners/ansible/config/guest.rb @@ -11,7 +11,6 @@ module VagrantPlugins attr_accessor :install attr_accessor :install_mode attr_accessor :pip_args - attr_accessor :version def initialize super @@ -21,7 +20,6 @@ module VagrantPlugins @pip_args = UNSET_VALUE @provisioning_path = UNSET_VALUE @tmp_path = UNSET_VALUE - @version = UNSET_VALUE end def finalize! @@ -32,7 +30,6 @@ module VagrantPlugins @pip_args = "" if @pip_args == UNSET_VALUE @provisioning_path = "/vagrant" if provisioning_path == UNSET_VALUE @tmp_path = "/tmp/vagrant-ansible" if tmp_path == UNSET_VALUE - @version = "" if @version == UNSET_VALUE end def validate(machine) diff --git a/plugins/provisioners/ansible/errors.rb b/plugins/provisioners/ansible/errors.rb index be9e55fb9..efc177ef8 100644 --- a/plugins/provisioners/ansible/errors.rb +++ b/plugins/provisioners/ansible/errors.rb @@ -23,8 +23,8 @@ module VagrantPlugins error_key(:cannot_support_pip_install) end - class AnsibleVersionNotFoundOnGuest < AnsibleError - error_key(:ansible_version_not_found_on_guest) + class AnsibleVersionMismatch < AnsibleError + error_key(:ansible_version_mismatch) end end end diff --git a/plugins/provisioners/ansible/provisioner/guest.rb b/plugins/provisioners/ansible/provisioner/guest.rb index 863095dbb..1b8fc38a4 100644 --- a/plugins/provisioners/ansible/provisioner/guest.rb +++ b/plugins/provisioners/ansible/provisioner/guest.rb @@ -65,7 +65,7 @@ module VagrantPlugins if (!config.version.empty? && config.version.to_s.to_sym != :latest && !@machine.guest.capability(:ansible_installed, config.version)) - raise Ansible::Errors::AnsibleVersionNotFoundOnGuest, required_version: config.version.to_s + raise Ansible::Errors::AnsibleVersionMismatch, system: "guest", required_version: config.version.to_s end end diff --git a/plugins/provisioners/ansible/provisioner/host.rb b/plugins/provisioners/ansible/provisioner/host.rb index 7682a2af3..f25178729 100644 --- a/plugins/provisioners/ansible/provisioner/host.rb +++ b/plugins/provisioners/ansible/provisioner/host.rb @@ -19,6 +19,7 @@ module VagrantPlugins @ssh_info = @machine.ssh_info warn_for_unsupported_platform + check_required_ansible_version unless config.version.empty? check_files_existence set_compatibility_mode @@ -36,6 +37,19 @@ module VagrantPlugins end end + def check_required_ansible_version + if config.version.to_s.to_sym == :latest + @logger.debug("The :latest version requirement is not supported (yet) by the host-based provisioner") + return + end + + @logger.info("Checking for Ansible version on Vagrant host...") + found_version = gather_ansible_version + if (!found_version || "ansible #{config.version}\n" != found_version.lines[0]) + raise Ansible::Errors::AnsibleVersionMismatch, system: "host", required_version: config.version.to_s + end + end + def prepare_command_arguments # Connect with native OpenSSH client # Other modes (e.g. paramiko) are not officially supported, diff --git a/templates/locales/en.yml b/templates/locales/en.yml index 66e297a5d..5cb65c0ad 100644 --- a/templates/locales/en.yml +++ b/templates/locales/en.yml @@ -2364,11 +2364,11 @@ en: to contribute back support. Thank you! https://github.com/mitchellh/vagrant - ansible_version_not_found_on_guest: |- - The requested Ansible version (%{required_version}) was not found on the guest. - Please check the ansible installation on your guest system, + ansible_version_mismatch: |- + The requested Ansible version (%{required_version}) was not found on the %{system}. + Please check the Ansible installation on your Vagrant %{system} system, or adapt the `version` option of this provisioner in your Vagrantfile. - See https://docs.vagrantup.com/v2/provisioning/ansible_local.html + See https://docs.vagrantup.com/v2/provisioning/ansible_common.html#version for more information. config_file_not_found: |- `%{config_option}` does not exist on the %{system}: %{path} diff --git a/test/unit/plugins/provisioners/ansible/config/guest_test.rb b/test/unit/plugins/provisioners/ansible/config/guest_test.rb index a9ea5d9da..19010ba94 100644 --- a/test/unit/plugins/provisioners/ansible/config/guest_test.rb +++ b/test/unit/plugins/provisioners/ansible/config/guest_test.rb @@ -16,7 +16,8 @@ describe VagrantPlugins::Ansible::Config::Guest do let(:existing_file) { "this/path/is/a/stub" } it "supports a list of options" do - supported_options = %w( become + supported_options = %w( + become become_user compatibility_mode config_file @@ -43,7 +44,8 @@ describe VagrantPlugins::Ansible::Config::Guest do tmp_path vault_password_file verbose - version ) + version + ) expect(get_provisioner_option_names(described_class)).to eql(supported_options) end @@ -58,7 +60,6 @@ describe VagrantPlugins::Ansible::Config::Guest do expect(subject.install_mode).to eql(:default) expect(subject.provisioning_path).to eql("/vagrant") expect(subject.tmp_path).to eql("/tmp/vagrant-ansible") - expect(subject.version).to be_empty end end diff --git a/test/unit/plugins/provisioners/ansible/config/host_test.rb b/test/unit/plugins/provisioners/ansible/config/host_test.rb index 2e18005ee..b868d2648 100644 --- a/test/unit/plugins/provisioners/ansible/config/host_test.rb +++ b/test/unit/plugins/provisioners/ansible/config/host_test.rb @@ -13,7 +13,8 @@ describe VagrantPlugins::Ansible::Config::Host, :skip_windows => true do let(:existing_file) { File.expand_path(__FILE__) } it "supports a list of options" do - supported_options = %w( ask_become_pass + supported_options = %w( + ask_become_pass ask_sudo_pass ask_vault_pass become @@ -40,7 +41,9 @@ describe VagrantPlugins::Ansible::Config::Host, :skip_windows => true do sudo_user tags vault_password_file - verbose ) + verbose + version + ) expect(get_provisioner_option_names(described_class)).to eql(supported_options) end diff --git a/test/unit/plugins/provisioners/ansible/config/shared.rb b/test/unit/plugins/provisioners/ansible/config/shared.rb index 659573af3..16902a138 100644 --- a/test/unit/plugins/provisioners/ansible/config/shared.rb +++ b/test/unit/plugins/provisioners/ansible/config/shared.rb @@ -25,6 +25,7 @@ shared_examples_for 'options shared by both Ansible provisioners' do expect(subject.tags).to be_nil expect(subject.vault_password_file).to be_nil expect(subject.verbose).to be(false) + expect(subject.version).to be_empty end end diff --git a/test/unit/plugins/provisioners/ansible/provisioner_test.rb b/test/unit/plugins/provisioners/ansible/provisioner_test.rb index 7e8c3aaaa..eafd8bf79 100644 --- a/test/unit/plugins/provisioners/ansible/provisioner_test.rb +++ b/test/unit/plugins/provisioners/ansible/provisioner_test.rb @@ -947,6 +947,46 @@ VF end end + + context "with version option set" do + before do + config.version = "2.3.4.5" + end + + describe "and the installed ansible version is correct" do + before do + allow(subject).to receive(:gather_ansible_version).and_return("ansible #{config.version}\n...\n") + end + + it "executes ansible-playbook command" do + expect(Vagrant::Util::Subprocess).to receive(:execute).with('ansible-playbook', any_args).and_return(default_execute_result) + end + end + + describe "and there is an ansible version mismatch" do + before do + allow(subject).to receive(:gather_ansible_version).and_return("ansible 1.9.6\n...\n") + end + + it "raises an error about the ansible version mismatch", skip_before: true, skip_after: true do + config.finalize! + expect {subject.provision}.to raise_error(VagrantPlugins::Ansible::Errors::AnsibleVersionMismatch) + end + end + + describe "and the installed ansible version cannot be detected" do + before do + allow(subject).to receive(:gather_ansible_version).and_return(nil) + end + + it "raises an error about the ansible version mismatch", skip_before: true, skip_after: true do + config.finalize! + expect {subject.provision}.to raise_error(VagrantPlugins::Ansible::Errors::AnsibleVersionMismatch) + end + end + end + + # TODO: add more tests, now that we know how to deal with multiple Subprocess stub executions describe "with galaxy support" do before do diff --git a/website/source/docs/provisioning/ansible_common.html.md b/website/source/docs/provisioning/ansible_common.html.md index fbfa0e96c..17c047992 100644 --- a/website/source/docs/provisioning/ansible_common.html.md +++ b/website/source/docs/provisioning/ansible_common.html.md @@ -42,7 +42,7 @@ Some of these options are for advanced usage only and should not be used unless