provisioners/ansible: Move `version` to common options

Before this change, only the ansible_local provisioner supported this
option (for ansible version requirement, and pip installation). Now, the
ansible host-based provisioner can also require a exact ansible version.

Resolve #8914

Note: this has been added as part of #6570 resolution, since the
introduction of the `compatibility_mode` auto-detection made both
provisioners made capable to detect ansible version.

Pending: optimize the code to avoid duplicated executions of "ansible
--version" command.
This commit is contained in:
Gilles Cornu 2017-08-29 05:32:38 +02:00
parent 15e74e264d
commit 8c0df3d046
No known key found for this signature in database
GPG Key ID: F6BC2CF7E1FE8FFF
12 changed files with 91 additions and 32 deletions

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -42,7 +42,7 @@ Some of these options are for advanced usage only and should not be used unless
<div class="alert alert-warning">
<strong>Attention:</strong>
Vagrant doesn't perform any validation between the `compatibility_mode` value and the value of the ansible_local [`version`](/docs/provisioning/ansible_local.html#version) option.
Vagrant doesn't perform any validation between the `compatibility_mode` value and the value of the [`version`](#version) option.
</div>
- `config_file` (string) - The path to an [Ansible Configuration file](https://docs.ansible.com/intro_configuration.html).
@ -185,3 +185,16 @@ Some of these options are for advanced usage only and should not be used unless
Examples: `true` (equivalent to `v`), `-vvv` (equivalent to `vvv`), `vvvv`.
Note that when the `verbose` option is enabled, the `ansible-playbook` command used by Vagrant will be displayed.
- `version` (string) - The expected Ansible version.
This option is disabled by default.
When an Ansible version is defined (e.g. `"2.1.6.0"`), the Ansible provisioner will be executed only if Ansible is installed at the requested version.
When this option is set to `"latest"`, no version check is applied.
<div class="alert alert-info">
<strong>Tip:</strong>
With the `ansible_local` provisioner, it is currently possible to use this option to specify which version of Ansible must be automatically installed, but <strong>only</strong> in combination with the [**`install_mode`**](ansible_local.html#install_mode) set to <strong>`:pip`</strong>.
</div>

View File

@ -62,8 +62,8 @@ This section lists the _specific_ options for the Ansible Local provisioner. In
Vagrant will try to install (or upgrade) Ansible when one of these conditions are met:
- Ansible is not installed (or cannot be found).
- The `version` option is set to `"latest"`.
- The current Ansible version does not correspond to the `version` option.
- The [`version`](/docs/provisioning/ansible_common.html#version) option is set to `"latest"`.
- The current Ansible version does not correspond to the [`version`](/docs/provisioning/ansible_common.html#version) option.
<div class="alert alert-warning">
<strong>Attention:</strong>
@ -76,7 +76,7 @@ This section lists the _specific_ options for the Ansible Local provisioner. In
- On Ubuntu-like systems, the latest Ansible release is installed from the `ppa:ansible/ansible` repository.
- On RedHat-like systems, the latest Ansible release is installed from the [EPEL](http://fedoraproject.org/wiki/EPEL) repository.
- `:pip`: Ansible is installed from [PyPI](https://pypi.python.org/pypi) with [pip](https://pip.pypa.io) package installer. With this mode, Vagrant will systematically try to [install the latest pip version](https://pip.pypa.io/en/stable/installing/#installing-with-get-pip-py). With the `:pip` mode you can optionally install a specific Ansible release by setting the [`version`](#version) option.
- `:pip`: Ansible is installed from [PyPI](https://pypi.python.org/pypi) with [pip](https://pip.pypa.io) package installer. With this mode, Vagrant will systematically try to [install the latest pip version](https://pip.pypa.io/en/stable/installing/#installing-with-get-pip-py). With the `:pip` mode you can optionally install a specific Ansible release by setting the [`version`](/docs/provisioning/ansible_common.html#version) option.
Example:
@ -141,19 +141,6 @@ This section lists the _specific_ options for the Ansible Local provisioner. In
The default value is `/tmp/vagrant-ansible`
- `version` (string) - The expected Ansible version.
This option is disabled by default.
When an Ansible version is defined (e.g. `"1.8.2"`), the Ansible local provisioner will be executed only if Ansible is installed at the requested version.
When this option is set to `"latest"`, no version check is applied.
<div class="alert alert-info">
<strong>Tip:</strong>
It is currently possible to use this option to specify which version of Ansible must be automatically installed, but <strong>only</strong> in combination with the `install_mode` set to <strong>`:pip`</strong>.
</div>
## Tips and Tricks
### Ansible Parallel Execution from a Guest