Repository: ansible/ansible

Issue:
ansible_ssh_extra_args is ignored when ansible_ssh_executable is set
##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
ssh

##### ANSIBLE VERSION
```
$ ansible --version
ansible 2.2.1.0
  config file = /work/ansible-ssh-pubkey-login-role/ansible.cfg
  configured module search path = Default w/o overrides
```

##### CONFIGURATION
N/A

##### OS / ENVIRONMENT
running from Ubuntu.
no remoting OS

##### SUMMARY
when set ansible_ssh_executable in a task, the result params only contains ansible_ssh_common_args, but not ansible_ssh_extra_args.

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

```yaml
---
- hosts: all
  gather_facts: False
  tasks:
  - raw: exit
    vars:
    - ansible_ssh_executable: echo
    - ansible_ssh_common_args: AA
    - ansible_ssh_extra_args: BB
    register: test
  - debug: msg="{{test.stdout_lines}}"
```

```
$ cat inv
github.com

$ ansible-playbook -i inv pl.yml
```

##### EXPECTED RESULTS

PLAY [all] *********************************************************************

TASK [raw] *********************************************************************
changed: [github.com]

TASK [debug] *******************************************************************
ok: [github.com] => {
    "msg": [
        "-C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 **AA BB** -o ControlPath=/home/james/.ansible/cp/ansible-ssh-%h-%p-%r -tt github.com exit"
    ]
}

PLAY RECAP *********************************************************************
github.com                 : ok=2    changed=1    unreachable=0    failed=0 

##### ACTUAL RESULTS


PLAY [all] *********************************************************************

TASK [raw] *********************************************************************
changed: [github.com]

TASK [debug] *******************************************************************
ok: [github.com] => {
    "msg": [
        "-C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 **AA** -o ControlPath=/home/james/.ansible/cp/ansible-ssh-%h-%p-%r -tt github.com exit"
    ]
}

PLAY RECAP *********************************************************************
github.com                 : ok=2    changed=1    unreachable=0    failed=0 




Discussion:

Resolving patch:
diff --git a/lib/ansible/plugins/connection/ssh.py b/lib/ansible/plugins/connection/ssh.py
--- a/lib/ansible/plugins/connection/ssh.py
+++ b/lib/ansible/plugins/connection/ssh.py
@@ -158,7 +158,10 @@ def _build_command(self, binary, *other_args):
             self.sshpass_pipe = os.pipe()
             b_command += [b'sshpass', b'-d' + to_bytes(self.sshpass_pipe[0], nonstring='simplerepr', errors='surrogate_or_strict')]
 
-        b_command += [to_bytes(binary, errors='surrogate_or_strict')]
+        if binary == 'ssh':
+            b_command += [to_bytes(self._play_context.ssh_executable, errors='surrogate_or_strict')]
+        else:
+            b_command += [to_bytes(binary, errors='surrogate_or_strict')]
 
         #
         # Next, additional arguments based on the configuration.
@@ -608,13 +611,10 @@ def _exec_command(self, cmd, in_data=None, sudoable=True):
         # data into /usr/bin/python inside a tty automatically invokes the
         # python interactive-mode but the modules are not compatible with the
         # interactive-mode ("unexpected indent" mainly because of empty lines)
-
-        ssh_executable = self._play_context.ssh_executable
-
         if not in_data and sudoable:
-            args = (ssh_executable, '-tt', self.host, cmd)
+            args = ('ssh', '-tt', self.host, cmd)
         else:
-            args = (ssh_executable, self.host, cmd)
+            args = ('ssh', self.host, cmd)
 
         cmd = self._build_command(*args)
         (returncode, stdout, stderr) = self._run(cmd, in_data, sudoable=sudoable)
@@ -773,7 +773,7 @@ def close(self):
         # temporarily disabled as we are forced to currently close connections after every task because of winrm
         # if self._connected and self._persistent:
         #     ssh_executable = self._play_context.ssh_executable
-        #     cmd = self._build_command(ssh_executable, '-O', 'stop', self.host)
+        #     cmd = self._build_command('ssh', '-O', 'stop', self.host)
         #
         #     cmd = map(to_bytes, cmd)
         #     p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)


Test patch: