Merge pull request #7918 from mitchellh/gildegoma/fix-7195

Add `config_file` option to both Ansible provisioners
This commit is contained in:
Gilles Cornu 2016-11-15 08:29:30 +01:00 committed by GitHub
commit 8caed8ea16
10 changed files with 108 additions and 56 deletions

View File

@ -6,6 +6,7 @@ module VagrantPlugins
GALAXY_COMMAND_DEFAULT = "ansible-galaxy install --role-file=%{role_file} --roles-path=%{roles_path} --force".freeze
PLAYBOOK_COMMAND_DEFAULT = "ansible-playbook".freeze
attr_accessor :config_file
attr_accessor :extra_vars
attr_accessor :galaxy_role_file
attr_accessor :galaxy_roles_path
@ -26,6 +27,7 @@ module VagrantPlugins
attr_accessor :verbose
def initialize
@config_file = UNSET_VALUE
@extra_vars = UNSET_VALUE
@galaxy_role_file = UNSET_VALUE
@galaxy_roles_path = UNSET_VALUE
@ -47,6 +49,7 @@ module VagrantPlugins
end
def finalize!
@config_file = nil if @config_file == UNSET_VALUE
@extra_vars = nil if @extra_vars == UNSET_VALUE
@galaxy_role_file = nil if @galaxy_role_file == UNSET_VALUE
@galaxy_roles_path = nil if @galaxy_roles_path == UNSET_VALUE

View File

@ -29,20 +29,39 @@ module VagrantPlugins
check_path_is_a_file(config.playbook, :playbook)
check_path_exists(config.inventory_path, :inventory_path) if config.inventory_path
check_path_is_a_file(config.config_file, :config_file) if config.config_file
check_path_is_a_file(config.extra_vars[1..-1], :extra_vars) if has_an_extra_vars_file_argument
check_path_is_a_file(config.galaxy_role_file, :galaxy_role_file) if config.galaxy_role_file
check_path_is_a_file(config.vault_password_file, :vault_password_file) if config.vault_password_file
end
def ansible_playbook_command_for_shell_execution
shell_command = []
def get_environment_variables_for_shell_execution
shell_env_vars = []
@environment_variables.each_pair do |k, v|
if k =~ /ANSIBLE_SSH_ARGS|ANSIBLE_ROLES_PATH/
shell_command << "#{k}='#{v}'"
if k =~ /ANSIBLE_SSH_ARGS|ANSIBLE_ROLES_PATH|ANSIBLE_CONFIG/
shell_env_vars << "#{k}='#{v}'"
else
shell_command << "#{k}=#{v}"
shell_env_vars << "#{k}=#{v}"
end
end
shell_env_vars
end
def ansible_galaxy_command_for_shell_execution
command_values = {
role_file: "'#{get_galaxy_role_file}'",
roles_path: "'#{get_galaxy_roles_path}'"
}
shell_command = get_environment_variables_for_shell_execution
shell_command << config.galaxy_command % command_values
shell_command.flatten.join(' ')
end
def ansible_playbook_command_for_shell_execution
shell_command = get_environment_variables_for_shell_execution
shell_command << config.playbook_command
@ -102,6 +121,12 @@ module VagrantPlugins
# Use ANSIBLE_ROLES_PATH to tell ansible-playbook where to look for roles
# (there is no equivalent command line argument in ansible-playbook)
@environment_variables["ANSIBLE_ROLES_PATH"] = get_galaxy_roles_path if config.galaxy_roles_path
prepare_ansible_config_environment_variable
end
def prepare_ansible_config_environment_variable
@environment_variables["ANSIBLE_CONFIG"] = config.config_file if config.config_file
end
# Auto-generate "safe" inventory file based on Vagrantfile,

View File

@ -72,14 +72,9 @@ module VagrantPlugins
end
def execute_ansible_galaxy_on_guest
command_values = {
role_file: "'#{get_galaxy_role_file}'",
roles_path: "'#{get_galaxy_roles_path}'"
}
prepare_ansible_config_environment_variable
remote_command = config.galaxy_command % command_values
execute_ansible_command_on_guest "galaxy", remote_command
execute_ansible_command_on_guest "galaxy", ansible_galaxy_command_for_shell_execution
end
def execute_ansible_playbook_on_guest

View File

@ -20,6 +20,7 @@ module VagrantPlugins
check_files_existence
warn_for_unsupported_platform
execute_ansible_galaxy_from_host if config.galaxy_role_file
execute_ansible_playbook_from_host
end
@ -88,6 +89,8 @@ module VagrantPlugins
end
def execute_ansible_galaxy_from_host
prepare_ansible_config_environment_variable
command_values = {
role_file: get_galaxy_role_file,
roles_path: get_galaxy_roles_path
@ -97,20 +100,20 @@ module VagrantPlugins
command = str_command.split(VAGRANT_ARG_SEPARATOR)
command << {
env: @environment_variables,
# Write stdout and stderr data, since it's the regular Ansible output
notify: [:stdout, :stderr],
workdir: @machine.env.root_path.to_s
}
# FIXME: role_file and roles_path arguments should be quoted in the console output
ui_running_ansible_command "galaxy", str_command.gsub(VAGRANT_ARG_SEPARATOR, ' ')
ui_running_ansible_command "galaxy", ansible_galaxy_command_for_shell_execution
execute_command_from_host command
end
def execute_ansible_playbook_from_host
prepare_command_arguments
prepare_environment_variables
prepare_command_arguments
# Assemble the full ansible-playbook command
command = [config.playbook_command] << @command_arguments
@ -234,6 +237,7 @@ module VagrantPlugins
proxy_cmd += " exec nc %h %p 2>/dev/null"
ssh_options << "-o ProxyCommand='#{ proxy_cmd }'"
# TODO ssh_options << "-o ProxyCommand=\"#{ proxy_cmd }\""
end
# Use an SSH ProxyCommand when corresponding Vagrant setting is defined

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( extra_vars
supported_options = %w( config_file
extra_vars
galaxy_command
galaxy_role_file
galaxy_roles_path

View File

@ -15,6 +15,7 @@ describe VagrantPlugins::Ansible::Config::Host, :skip_windows => true do
it "supports a list of options" do
supported_options = %w( ask_sudo_pass
ask_vault_pass
config_file
extra_vars
force_remote_user
galaxy_command

View File

@ -3,6 +3,7 @@ shared_examples_for 'options shared by both Ansible provisioners' do
it "assigns default values to unset common options" do
subject.finalize!
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")
expect(subject.galaxy_role_file).to be_nil

View File

@ -59,8 +59,6 @@ VF
stubbed_ui.stub(detail: "")
machine.env.stub(ui: stubbed_ui)
subject.stub(:check_path)
config.playbook = 'playbook.yml'
end
@ -195,7 +193,9 @@ VF
before do
unless example.metadata[:skip_before]
config.finalize!
Vagrant::Util::Subprocess.stub(execute: Vagrant::Util::Subprocess::Result.new(0, "", ""))
subject.stub(:check_path)
end
end
@ -207,37 +207,37 @@ VF
describe 'checking existence of Ansible configuration files' do
describe 'when the playbook file does not exist' do
it "raises an error", skip_before: true, skip_after: true do
STUBBED_INVALID_PATH = "/test/239nfmd/invalid_path".freeze
it 'raises an error when the `playbook` file does not exist', skip_before: true, skip_after: true do
subject.stub(:check_path).and_raise(VagrantPlugins::Ansible::Errors::AnsibleError,
_key: :config_file_not_found,
config_option: "playbook",
path: "/home/wip/test/invalid_path.yml",
path: STUBBED_INVALID_PATH,
system: "host")
config.playbook = "/home/wip/test/invalid_path.yml"
config.playbook = STUBBED_INVALID_PATH
config.finalize!
expect {subject.provision}.to raise_error(VagrantPlugins::Ansible::Errors::AnsibleError,
"`playbook` does not exist on the host: /home/wip/test/invalid_path.yml")
end
"`playbook` does not exist on the host: #{STUBBED_INVALID_PATH}")
end
describe 'when the inventory path does not exist' do
it "raises an error"
end
%w(config_file extra_vars inventory_path galaxy_role_file vault_password_file).each do |option_name|
it "raises an error when the '#{option_name}' does not exist", skip_before: true, skip_after: true do
Vagrant::Util::Subprocess.stub(execute: Vagrant::Util::Subprocess::Result.new(0, "", ""))
describe 'when the extra_vars file does not exist' do
it "raises an error"
config.playbook = existing_file
config.send(option_name + '=', STUBBED_INVALID_PATH)
if option_name == 'extra_vars'
# little trick to auto-append the '@' prefix, which is a duty of the config validator...
config.validate(machine)
end
config.finalize!
describe 'when the galaxy_role_file does not exist' do
it "raises an error"
expect {subject.provision}.to raise_error(VagrantPlugins::Ansible::Errors::AnsibleError,
"`#{option_name}` does not exist on the host: #{STUBBED_INVALID_PATH}")
end
describe 'when the vault_password_file does not exist' do
it "raises an error"
end
end
@ -245,6 +245,8 @@ VF
describe 'when ansible-playbook fails' do
it "raises an error", skip_before: true, skip_after: true do
config.finalize!
subject.stub(:check_path)
Vagrant::Util::Subprocess.stub(execute: Vagrant::Util::Subprocess::Result.new(1, "", ""))
expect {subject.provision}.to raise_error(VagrantPlugins::Ansible::Errors::AnsibleCommandFailed)
@ -582,6 +584,20 @@ VF
end
end
context "with config_file option defined" do
before do
config.config_file = existing_file
end
it "sets ANSIBLE_CONFIG environment variable" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
cmd_opts = args.last
expect(cmd_opts[:env]).to include("ANSIBLE_CONFIG")
expect(cmd_opts[:env]['ANSIBLE_CONFIG']).to eql(existing_file)
}
end
end
describe "with ask_vault_pass option" do
before do
config.ask_vault_pass = true
@ -777,6 +793,8 @@ VF
it "raises an error when ansible-galaxy command fails", skip_before: true, skip_after: true do
config.finalize!
subject.stub(:check_path)
Vagrant::Util::Subprocess.stub(execute: Vagrant::Util::Subprocess::Result.new(1, "", ""))
expect {subject.provision}.to raise_error(VagrantPlugins::Ansible::Errors::AnsibleCommandFailed)
@ -852,11 +870,12 @@ VF
config.raw_arguments = ["--why-not", "--su-user=foot", "--ask-su-pass", "--limit=all", "--private-key=./myself.key", "--extra-vars='{\"var3\":\"foo\"}'"]
# environment variables
config.config_file = existing_file
config.host_key_checking = true
config.raw_ssh_args = ['-o ControlMaster=no']
end
it_should_set_arguments_and_environment_variables 21, 5, true
it_should_set_arguments_and_environment_variables 21, 6, true
it_should_explicitly_enable_ansible_ssh_control_persist_defaults
it_should_set_optional_arguments({ "extra_vars" => "--extra-vars={\"var1\":\"string with 'apostrophes', \\\\, \\\" and =\",\"var2\":{\"x\":42}}",
"sudo" => "--sudo",
@ -883,7 +902,7 @@ VF
it "shows the ansible-playbook command, with additional quotes when required" do
expect(machine.env.ui).to receive(:detail).with { |full_command|
expect(full_command).to eq(%Q(PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_ROLES_PATH='/up/to the stars' ANSIBLE_HOST_KEY_CHECKING=true ANSIBLE_SSH_ARGS='-o IdentitiesOnly=yes -i '/my/key1' -i '/my/key2' -o ForwardAgent=yes -o ControlMaster=no -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --connection=ssh --timeout=30 --ask-sudo-pass --ask-vault-pass --limit="machine*:&vagrant:!that_one" --inventory-file=#{generated_inventory_dir} --extra-vars="{\\"var1\\":\\"string with 'apostrophes', \\\\\\\\, \\\\\\" and =\\",\\"var2\\":{\\"x\\":42}}" --sudo --sudo-user=deployer -vvv --vault-password-file=#{File.expand_path(__FILE__)} --tags=db,www --skip-tags=foo,bar --start-at-task="joe's awesome task" --why-not --su-user=foot --ask-su-pass --limit=all --private-key=./myself.key --extra-vars='{\"var3\":\"foo\"}' playbook.yml))
expect(full_command).to eq(%Q(PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_ROLES_PATH='/up/to the stars' ANSIBLE_CONFIG='#{existing_file}' ANSIBLE_HOST_KEY_CHECKING=true ANSIBLE_SSH_ARGS='-o IdentitiesOnly=yes -i '/my/key1' -i '/my/key2' -o ForwardAgent=yes -o ControlMaster=no -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --connection=ssh --timeout=30 --ask-sudo-pass --ask-vault-pass --limit="machine*:&vagrant:!that_one" --inventory-file=#{generated_inventory_dir} --extra-vars="{\\"var1\\":\\"string with 'apostrophes', \\\\\\\\, \\\\\\" and =\\",\\"var2\\":{\\"x\\":42}}" --sudo --sudo-user=deployer -vvv --vault-password-file=#{existing_file} --tags=db,www --skip-tags=foo,bar --start-at-task="joe's awesome task" --why-not --su-user=foot --ask-su-pass --limit=all --private-key=./myself.key --extra-vars='{\"var3\":\"foo\"}' playbook.yml))
}
end
end

View File

@ -17,6 +17,10 @@ These options get passed to the `ansible-playbook` command that ships with Ansib
Some of these options are for advanced usage only and should not be used unless you understand their purpose.
- `config_file` (string) - The path to an [Ansible Configuration file](https://docs.ansible.com/intro_configuration.html).
By default, this option is not set, and Ansible will [search for a possible configuration file in some default locations](/docs/provisioning/ansible_intro.html#ANSIBLE_CONFIG).
- `extra_vars` (string or hash) - Pass additional variables (with highest priority) to the playbook.
This parameter can be a path to a JSON or YAML file, or a hash.

View File

@ -246,12 +246,11 @@ Certain settings in Ansible are (only) adjustable via a [configuration file](htt
When shipping an Ansible configuration file it is good to know that:
- it is possible to reference an Ansible configuration file via `ANSIBLE_CONFIG` environment variable, if you want to be flexible about the location of this file.
- as of Ansible 1.5, the lookup order is the following:
- `ANSIBLE_CONFIG` an environment variable
- any path set as `ANSIBLE_CONFIG` environment variable
- `ansible.cfg` in the runtime working directory
- `.ansible.cfg` in the user home directory
- `/etc/ansible/ansible.cfg`
- `ansible-playbook` doesn't look for a configuration file relative to the playbook file location (e.g. in the same directory)
- Ansible commands don't look for a configuration file relative to the playbook file location (e.g. in the same directory)
- an `ansible.cfg` file located in the same directory as your `Vagrantfile` will be used by default.
- it is also possible to reference any other location with the [config_file](/docs/provisioning/ansible_common.html#config_file) provisioner option. In this case, Vagrant will set the `ANSIBLE_CONFIG` environment variable accordingly.