From a7dfc73b85331a1966cf3a29a7bc7b83fc07768b Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Sat, 11 Jun 2016 07:28:05 +0200 Subject: [PATCH] provisioners/ansible: honor galaxy_roles_path when running ansible-playbook This commit include the following changes: - systematically set ANSIBLE_ROLES_PATH environment variable when galaxy_roles_path is defined. - slightly refactor to introduce the concept of "provisioning working directory" (possible usage in the future for resolving GH-7195) - fix a bug in ansible-galaxy execution by the ansible_local provisioner if the paths contains blank characters. Fix #7269 --- .../provisioners/ansible/provisioner/base.rb | 13 +++++++++---- .../provisioners/ansible/provisioner/guest.rb | 8 ++++++-- .../provisioners/ansible/provisioner/host.rb | 9 +++++++-- .../provisioners/ansible/provisioner_test.rb | 19 +++++++++++++++++-- 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/plugins/provisioners/ansible/provisioner/base.rb b/plugins/provisioners/ansible/provisioner/base.rb index 786210474..bbfaa5290 100644 --- a/plugins/provisioners/ansible/provisioner/base.rb +++ b/plugins/provisioners/ansible/provisioner/base.rb @@ -37,7 +37,7 @@ module VagrantPlugins def ansible_playbook_command_for_shell_execution shell_command = [] @environment_variables.each_pair do |k, v| - if k == 'ANSIBLE_SSH_ARGS' + if k =~ /ANSIBLE_SSH_ARGS|ANSIBLE_ROLES_PATH/ shell_command << "#{k}='#{v}'" else shell_command << "#{k}=#{v}" @@ -98,6 +98,10 @@ module VagrantPlugins # Setting ANSIBLE_NOCOLOR is "unnecessary" at the moment, but this could change in the future # (e.g. local provisioner [GH-2103], possible change in vagrant/ansible integration, etc.) @environment_variables["ANSIBLE_NOCOLOR"] = "true" if !@machine.env.ui.color? + + # 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 end # Auto-generate "safe" inventory file based on Vagrantfile, @@ -221,11 +225,12 @@ module VagrantPlugins end end - def get_galaxy_role_file(base_dir) - Helpers::expand_path_in_unix_style(config.galaxy_role_file, base_dir) + def get_galaxy_role_file + Helpers::expand_path_in_unix_style(config.galaxy_role_file, get_provisioning_working_directory) end - def get_galaxy_roles_path(base_dir) + def get_galaxy_roles_path + base_dir = get_provisioning_working_directory if config.galaxy_roles_path Helpers::expand_path_in_unix_style(config.galaxy_roles_path, base_dir) else diff --git a/plugins/provisioners/ansible/provisioner/guest.rb b/plugins/provisioners/ansible/provisioner/guest.rb index b94445619..3f8aa87c4 100644 --- a/plugins/provisioners/ansible/provisioner/guest.rb +++ b/plugins/provisioners/ansible/provisioner/guest.rb @@ -67,10 +67,14 @@ module VagrantPlugins end end + def get_provisioning_working_directory + config.provisioning_path + end + def execute_ansible_galaxy_on_guest command_values = { - role_file: get_galaxy_role_file(config.provisioning_path), - roles_path: get_galaxy_roles_path(config.provisioning_path) + role_file: "'#{get_galaxy_role_file}'", + roles_path: "'#{get_galaxy_roles_path}'" } remote_command = config.galaxy_command % command_values diff --git a/plugins/provisioners/ansible/provisioner/host.rb b/plugins/provisioners/ansible/provisioner/host.rb index 5b35749d1..929c66542 100644 --- a/plugins/provisioners/ansible/provisioner/host.rb +++ b/plugins/provisioners/ansible/provisioner/host.rb @@ -89,8 +89,8 @@ module VagrantPlugins def execute_ansible_galaxy_from_host command_values = { - role_file: get_galaxy_role_file(machine.env.root_path), - roles_path: get_galaxy_roles_path(machine.env.root_path) + role_file: get_galaxy_role_file, + roles_path: get_galaxy_roles_path } command_template = config.galaxy_command.gsub(' ', VAGRANT_ARG_SEPARATOR) str_command = command_template % command_values @@ -102,6 +102,7 @@ module VagrantPlugins 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, ' ') execute_command_from_host command @@ -188,6 +189,10 @@ module VagrantPlugins return machines end + def get_provisioning_working_directory + machine.env.root_path + end + def get_inventory_ssh_machine(machine, ssh_info) forced_remote_user = "" if config.force_remote_user diff --git a/test/unit/plugins/provisioners/ansible/provisioner_test.rb b/test/unit/plugins/provisioners/ansible/provisioner_test.rb index 4a916cae2..3f35477e5 100644 --- a/test/unit/plugins/provisioners/ansible/provisioner_test.rb +++ b/test/unit/plugins/provisioners/ansible/provisioner_test.rb @@ -771,6 +771,20 @@ VF end end + context "with galaxy_roles_path option defined" do + before do + config.galaxy_roles_path = "my-roles" + end + + it "sets ANSIBLE_ROLES_PATH with corresponding absolute path" do + expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args| + cmd_opts = args.last + expect(cmd_opts[:env]).to include("ANSIBLE_ROLES_PATH") + expect(cmd_opts[:env]['ANSIBLE_ROLES_PATH']).to eql(File.join(machine.env.root_path, "my-roles")) + } + end + end + context "with extra_vars option defined" do describe "with a hash value" do before do @@ -798,6 +812,7 @@ VF ssh_info[:private_key_path] = ['/my/key1', '/my/key2'] # command line arguments + config.galaxy_roles_path = "/up/to the stars" config.extra_vars = { var1: %Q(string with 'apostrophes', \\, " and =), var2: { x: 42 } } config.sudo = true config.sudo_user = 'deployer' @@ -816,7 +831,7 @@ VF config.raw_ssh_args = ['-o ControlMaster=no'] end - it_should_set_arguments_and_environment_variables 21, 4, true + it_should_set_arguments_and_environment_variables 21, 5, 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", @@ -843,7 +858,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_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_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)) } end end