From ca1e30d4054d1742329df462a4fc70479c15061e Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Mon, 10 Feb 2014 10:23:10 +0100 Subject: [PATCH 1/4] Ansible: Support multiple private keys Note that this feature requires to force `--connection=ssh`. This is not a big deal as `paramiko` mode is deprecated and in most cases `smart` mode enables `ssh` mode. --- plugins/provisioners/ansible/provisioner.rb | 42 +++++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb index 51d6f5a6c..cd716f00d 100644 --- a/plugins/provisioners/ansible/provisioner.rb +++ b/plugins/provisioners/ansible/provisioner.rb @@ -5,11 +5,10 @@ module VagrantPlugins @logger = Log4r::Logger.new("vagrant::provisioners::ansible") ssh = @machine.ssh_info - # Connect with Vagrant user (unless --user or --private-key are - # overidden by 'raw_arguments'). - # - # TODO: multiple private key support - options = %W[--private-key=#{ssh[:private_key_path][0]} --user=#{ssh[:username]}] + # Connect with Vagrant SSH identity, forcing 'ssh' ansible connection mode + # as 'paramiko' mode cannot support multiple keys. + # These default settings can be overridden by 'raw_arguments' option. + options = %W[--connection=ssh --private-key=#{ssh[:private_key_path][0]} --user=#{ssh[:username]}] # By default we limit by the current machine. # This can be overridden by the limit config option. @@ -33,15 +32,22 @@ module VagrantPlugins # Assemble the full ansible-playbook command command = (%w(ansible-playbook) << options << config.playbook).flatten + # Some Ansible options must be passed as environment variables + env = { + "ANSIBLE_FORCE_COLOR" => "true", + "ANSIBLE_HOST_KEY_CHECKING" => "#{config.host_key_checking}", + + # Ensure Ansible output isn't buffered so that we receive ouput + # on a task-by-task basis. + "PYTHONUNBUFFERED" => 1 + } + # Support Multiple SSH keys: + ansible_ssh_args = get_ansible_ssh_args + env["ANSIBLE_SSH_ARGS"] = ansible_ssh_args if !ansible_ssh_args.empty? + # Write stdout and stderr data, since it's the regular Ansible output command << { - :env => { - "ANSIBLE_FORCE_COLOR" => "true", - "ANSIBLE_HOST_KEY_CHECKING" => "#{config.host_key_checking}", - # Ensure Ansible output isn't buffered so that we receive ouput - # on a task-by-task basis. - "PYTHONUNBUFFERED" => 1 - }, + :env => env, :notify => [:stdout, :stderr], :workdir => @machine.env.root_path.to_s } @@ -149,6 +155,18 @@ module VagrantPlugins end end + def get_ansible_ssh_args + ssh = @machine.ssh_info + ssh_options = [] + + # Multiple Private Keys + ssh[:private_key_path].drop(1).each do |key| + ssh_options << "-o IdentityFile=#{key}" + end + + return ssh_options.join(' ') + end + def as_list_argument(v) v.kind_of?(Array) ? v.join(',') : v end From 9480edf05a14822629232307c3b1be96602d8656 Mon Sep 17 00:00:00 2001 From: Bryan Hunt Date: Mon, 10 Feb 2014 10:32:47 +0100 Subject: [PATCH 2/4] Ansible: Support SSH-Forwarding Credits: Problem was originally reported in https://github.com/mitchellh/vagrant/commit/dba02f35267ee90b540b0351ddb3fafa16608db8 by @picsolvebryan --- plugins/provisioners/ansible/provisioner.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb index cd716f00d..4ca0b369b 100644 --- a/plugins/provisioners/ansible/provisioner.rb +++ b/plugins/provisioners/ansible/provisioner.rb @@ -6,7 +6,7 @@ module VagrantPlugins ssh = @machine.ssh_info # Connect with Vagrant SSH identity, forcing 'ssh' ansible connection mode - # as 'paramiko' mode cannot support multiple keys. + # as 'paramiko' mode cannot support multiple keys and ssh-forwarding. # These default settings can be overridden by 'raw_arguments' option. options = %W[--connection=ssh --private-key=#{ssh[:private_key_path][0]} --user=#{ssh[:username]}] @@ -41,7 +41,7 @@ module VagrantPlugins # on a task-by-task basis. "PYTHONUNBUFFERED" => 1 } - # Support Multiple SSH keys: + # Support Multiple SSH keys and SSH forwarding: ansible_ssh_args = get_ansible_ssh_args env["ANSIBLE_SSH_ARGS"] = ansible_ssh_args if !ansible_ssh_args.empty? @@ -164,6 +164,9 @@ module VagrantPlugins ssh_options << "-o IdentityFile=#{key}" end + # SSH Forwarding + ssh_options << "-o ForwardAgent=yes" if ssh[:forward_agent] + return ssh_options.join(' ') end From db490c5da517cc2a25d1e5e3b8bab8ab488cf32c Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Mon, 10 Feb 2014 16:16:36 +0100 Subject: [PATCH 3/4] Ansible: force 'ssh' connection only when needed Remain in 'smart' mode, unless Multiple SSH identities or SSH-Forwarding are in use. --- plugins/provisioners/ansible/provisioner.rb | 30 +++++++++++++++------ 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb index 4ca0b369b..3706ffcac 100644 --- a/plugins/provisioners/ansible/provisioner.rb +++ b/plugins/provisioners/ansible/provisioner.rb @@ -5,19 +5,34 @@ module VagrantPlugins @logger = Log4r::Logger.new("vagrant::provisioners::ansible") ssh = @machine.ssh_info - # Connect with Vagrant SSH identity, forcing 'ssh' ansible connection mode - # as 'paramiko' mode cannot support multiple keys and ssh-forwarding. - # These default settings can be overridden by 'raw_arguments' option. - options = %W[--connection=ssh --private-key=#{ssh[:private_key_path][0]} --user=#{ssh[:username]}] + # + # 1) Default Settings (lowest precedence) + # + + # Connect with Vagrant SSH identity + options = %W[--private-key=#{ssh[:private_key_path][0]} --user=#{ssh[:username]}] + + # Multiple SSH keys and/or SSH forwarding can be passed via + # ANSIBLE_SSH_ARGS environment variable, which requires 'ssh' mode. + # Note that multiple keys and ssh-forwarding settings are not supported + # by deprecated 'paramiko' mode. + ansible_ssh_args = get_ansible_ssh_args + options << "--connection=ssh" unless ansible_ssh_args.empty? # By default we limit by the current machine. # This can be overridden by the limit config option. options << "--limit=#{@machine.name}" - # Joker! Not (yet) supported arguments can be passed this way. + # + # 2) Configuration Joker + # + options.concat(self.as_array(config.raw_arguments)) if config.raw_arguments - # Append Provisioner options (highest precedence): + # + # 3) Append Provisioner options (highest precedence): + # + options << "--inventory-file=#{self.setup_inventory_file}" options << "--extra-vars=#{self.get_extra_vars_argument}" if config.extra_vars options << "--sudo" if config.sudo @@ -42,8 +57,7 @@ module VagrantPlugins "PYTHONUNBUFFERED" => 1 } # Support Multiple SSH keys and SSH forwarding: - ansible_ssh_args = get_ansible_ssh_args - env["ANSIBLE_SSH_ARGS"] = ansible_ssh_args if !ansible_ssh_args.empty? + env["ANSIBLE_SSH_ARGS"] = ansible_ssh_args unless ansible_ssh_args.empty? # Write stdout and stderr data, since it's the regular Ansible output command << { From cf8bfb2347fd04399d50910e03052c4fb2ce7e21 Mon Sep 17 00:00:00 2001 From: Gilles Cornu Date: Fri, 28 Feb 2014 08:50:17 +0100 Subject: [PATCH 4/4] Ansible: Refactor handling of SSH vars/attributes Avoid repetitions by using (sometimes lazy loaded) instance attributes --- plugins/provisioners/ansible/provisioner.rb | 24 ++++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb index 3706ffcac..fe39f19d1 100644 --- a/plugins/provisioners/ansible/provisioner.rb +++ b/plugins/provisioners/ansible/provisioner.rb @@ -1,22 +1,27 @@ module VagrantPlugins module Ansible class Provisioner < Vagrant.plugin("2", :provisioner) - def provision + + def initialize(machine, config) + super + @logger = Log4r::Logger.new("vagrant::provisioners::ansible") - ssh = @machine.ssh_info + @ssh_info = @machine.ssh_info + end + + def provision # # 1) Default Settings (lowest precedence) # # Connect with Vagrant SSH identity - options = %W[--private-key=#{ssh[:private_key_path][0]} --user=#{ssh[:username]}] + options = %W[--private-key=#{@ssh_info[:private_key_path][0]} --user=#{@ssh_info[:username]}] # Multiple SSH keys and/or SSH forwarding can be passed via # ANSIBLE_SSH_ARGS environment variable, which requires 'ssh' mode. # Note that multiple keys and ssh-forwarding settings are not supported # by deprecated 'paramiko' mode. - ansible_ssh_args = get_ansible_ssh_args options << "--connection=ssh" unless ansible_ssh_args.empty? # By default we limit by the current machine. @@ -169,19 +174,22 @@ module VagrantPlugins end end + def ansible_ssh_args + @ansible_ssh_args ||= get_ansible_ssh_args + end + def get_ansible_ssh_args - ssh = @machine.ssh_info ssh_options = [] # Multiple Private Keys - ssh[:private_key_path].drop(1).each do |key| + @ssh_info[:private_key_path].drop(1).each do |key| ssh_options << "-o IdentityFile=#{key}" end # SSH Forwarding - ssh_options << "-o ForwardAgent=yes" if ssh[:forward_agent] + ssh_options << "-o ForwardAgent=yes" if @ssh_info[:forward_agent] - return ssh_options.join(' ') + ssh_options.join(' ') end def as_list_argument(v)