Repository: ansible/ansible

Issue:
become with password less sudo
Issue Type: Bug Report (2.0 regression)
Ansible Version: 2.0.0 (rc1)
Ansible Configuration: default
Environment: Ubuntu 14.04
Summary:
If become (sudo) password is provided and host is configured to allow password less sudo ansible times out.

Steps To Reproduce:
Enable password less sudo and try ansible-playbook with become: yes

Expected Results:
Playbook execution

Actual Results:
Fails in first step with timeout waiting for prompt



Discussion:
I tried this with the latest devel code and was unable to replicate with become: yes and  --ask-sudo-pass using this playbook:

```
- hosts: all
  become: yes
  become_user: foo
  tasks:
  - command: whoami
    register: whoami 
  - debug: msg="{{ whoami.stdout }}"
```

Is there any more information you may provide?

was password less sudo enabled on host? 
something like 

```
%sudo  ALL=(ALL:ALL) NOPASSWD: ALL
```

Sorry, I think there is something wrong in my config. Your playbook runs as expected with and without NOPASSWD:

I'll reopen this in case it's something else.

This only affects when used with ansible_ssh_pipelining: true or using pipelining in ansible.cfg

It works fine for me with devel@157230c3 with or without pipelining and with or without a sudo password. In any case, this ticket doesn't contain any details that could help to reproduce or debug the problem.

| NOPASSWD: | pipelining | result | ansible version |
| --- | --- | --- | --- |
| True | True | Fail | 2.0 (RC1) |
| True | False | Pass | 2.0 (RC1) |
| False | True | Pass | 2.0 (RC1) |
| True | True | Pass | 1.9.4 |
| True | False | Pass | 1.9.4 |
| False | True | Pass | 1.9.4 |

NOPASSWD: is setting in sudoers file on ansible_host
With this config simple playbook that @chrrrles suggested fails with NOPASSWD and pipelining.
And in all cases become is true and become password is provided to ansible

Sorry if I am not very clear where problem is.

Can you try with devel? And if it still fails, post full output with `ANSIBLE_DEBUG=1`?

```
Using ~/.ansible.cfg as config file
Vault password: 
[DEPRECATION WARNING]: Instead of sudo/sudo_user, use become/become_user and make sure become_method is 'sudo' (default). This feature will be removed 
in a future release. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
 28619 1448452636.89069: in VariableManager get_vars()
 28619 1448452636.89083: done with get_vars()
 28619 1448452636.89344: in VariableManager get_vars()
 28619 1448452636.89364: done with get_vars()
 28619 1448452636.89382: in VariableManager get_vars()
 28619 1448452636.89392: done with get_vars()
1 plays in ***
 28619 1448452637.01694: in VariableManager get_vars()
 28619 1448452637.01711: done with get_vars()
Loaded callback default of type stdout, v2.0
 28619 1448452637.02428: in VariableManager get_vars()
 28619 1448452637.02454: done with get_vars()

PLAY ***************************************************************************
 28619 1448452637.05690: getting the remaining hosts for this loop
 28619 1448452637.05712: done getting the remaining hosts for this loop
 28619 1448452637.05733: building list of next tasks for hosts
 28619 1448452637.05744: getting the next task for host test-vm
 28619 1448452637.05766: done getting next task for host test-vm
 28619 1448452637.05777:  ^ task is: TASK: setup 
 28619 1448452637.05787:  ^ state is: HOST STATE: block=0, task=0, rescue=0, always=0, role=None, run_state=1, fail_state=0, pending_setup=True, tasks child state? None, rescue child state? None, always child state? None
 28619 1448452637.05796: done building task lists
 28619 1448452637.05803: counting tasks in each state of execution
 28619 1448452637.05812: done counting tasks in each state of execution
 28619 1448452637.05820: advancing hosts in ITERATING_TASKS
 28619 1448452637.05828: starting to advance hosts
 28619 1448452637.05836: getting the next task for host test-vm
 28619 1448452637.05858: done getting next task for host test-vm
 28619 1448452637.05867:  ^ task is: TASK: setup 
 28619 1448452637.05876:  ^ state is: HOST STATE: block=0, task=0, rescue=0, always=0, role=None, run_state=1, fail_state=0, pending_setup=True, tasks child state? None, rescue child state? None, always child state? None
 28619 1448452637.05884: done advancing hosts to next task
 28619 1448452637.06052: getting variables
 28619 1448452637.06065: in VariableManager get_vars()
 28619 1448452637.06105: done with get_vars()
 28619 1448452637.06115: done getting variables
 28619 1448452637.06125: sending task start callback, copying the task so we can template it temporarily
 28619 1448452637.06134: done copying, going to template now
 28619 1448452637.06144: done templating
 28619 1448452637.06152: here goes the callback...

TASK [setup] *******************************************************************
 28619 1448452637.06171: sending task start callback
 28619 1448452637.06181: entering _queue_task() for test-vm/TASK: setup 
 28619 1448452637.06190: test-vm - putting task (TASK: setup ) in queue
 28619 1448452637.06199: worker is 1 (out of 1 available)
 28619 1448452637.06240: exiting _queue_task() for test-vm/TASK: setup 
 28619 1448452637.06664: done queuing things up, now waiting for results queue to drain
 28619 1448452637.06681: waiting for pending results...
 28626 1448452637.07370: there's work to be done! got a task/handler to work on: TASK: setup 
 28626 1448452637.07378: running TaskExecutor() for test-vm/TASK: setup 
 28626 1448452637.07383: in run()
 28626 1448452637.07444: calling self._execute()
 28626 1448452637.07943: starting attempt loop
 28626 1448452637.07968: running the handler
 28626 1448452637.08091: calling _low_level_execute_command() for command LANG=C LC_ALL=C LC_MESSAGES=C /usr/bin/python
 28626 1448452637.08108: in _low_level_execute_command() (LANG=C LC_ALL=C LC_MESSAGES=C /usr/bin/python)
 28626 1448452637.08118: using become for this command
 28626 1448452637.08142: executing the command /bin/sh -c 'sudo -H -S  -p "[sudo via testuser, key=zzmrwahkmtqhqhcqhwtwhyqppigdskyj] password: " -u root /bin/sh -c '"'"'echo BECOME-SUCCESS-zzmrwahkmtqhqhcqhwtwhyqppigdskyj; LANG=C LC_ALL=C LC_MESSAGES=C /usr/bin/python'"'"'' through the connection
<test-vm> ESTABLISH SSH CONNECTION FOR USER: testuser
<test-vm> SSH: ansible.cfg set ssh_args: (-o)(ControlMaster=auto)(-o)(ControlPersist=60s)
<test-vm> SSH: ANSIBLE_REMOTE_PORT/remote_port/ansible_port set: (-o)(Port=22)
<test-vm> SSH: ansible_password/ansible_ssh_pass not set: (-o)(KbdInteractiveAuthentication=no)(-o)(PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey)(-o)(PasswordAuthentication=no)
<test-vm> SSH: ANSIBLE_REMOTE_USER/remote_user/ansible_user/user/-u set: (-o)(User=testuser)
<test-vm> SSH: ANSIBLE_TIMEOUT/timeout set: (-o)(ConnectTimeout=10)
<test-vm> SSH: PlayContext set ssh_common_args: ()
<test-vm> SSH: PlayContext set ssh_extra_args: ()
<test-vm> SSH: found only ControlPersist; added ControlPath: (-o)(ControlPath=~/.ssh/ansible-ssh-%h-%p-%r)
<test-vm> SSH: EXEC ssh -C -vvv -o ControlMaster=auto -o ControlPersist=60s -o Port=22 -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User=testuser -o ConnectTimeout=10 -o 'ControlPath=~/.ssh/ansible-ssh-%h-%p-%r' test-vm /bin/sh -c 'sudo -H -S  -p "[sudo via testuser, key=zzmrwahkmtqhqhcqhwtwhyqppigdskyj] password: " -u root /bin/sh -c '"'"'echo BECOME-SUCCESS-zzmrwahkmtqhqhcqhwtwhyqppigdskyj; LANG=C LC_ALL=C LC_MESSAGES=C /usr/bin/python'"'"''
 28626 1448452637.08619: Initial state: awaiting_prompt: [sudo via testuser, key=zzmrwahkmtqhqhcqhwtwhyqppigdskyj] password: 
 28626 1448452637.09077: stderr chunk (state=0):
>>>OpenSSH_6.9p1 Debian-2+b1, OpenSSL 1.0.2d 9 Jul 2015
debug1: Reading configuration data ~/.ssh/config
<<<

 28626 1448452637.09154: stderr chunk (state=0):
>>>debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 19: Applying options for *
debug1: auto-mux: Trying existing master
debug2: fd 3 setting O_NONBLOCK
debug2: mux_client_hello_exchange: master version 4
debug3: mux_client_forwards: request forwardings: 0 local, 0 remote
debug3: mux_client_request_session: entering
debug3: mux_client_request_alive: entering
debug3: mux_client_request_alive: done pid = 27952
debug3: mux_client_request_session: session request sent
<<<

 28626 1448452637.09343: stderr chunk (state=0):
>>>debug1: mux_client_request_session: master session id: 2
<<<

 28626 1448452637.11634: stdout chunk (state=0):
>>>BECOME-SUCCESS-zzmrwahkmtqhqhcqhwtwhyqppigdskyj
<<<

 28626 1448452637.11670: become_success: (source=stdout, state=awaiting_prompt): 'BECOME-SUCCESS-zzmrwahkmtqhqhcqhwtwhyqppigdskyj'
 28626 1448452649.11869: done running TaskExecutor() for test-vm/TASK: setup 
 28626 1448452649.11879: sending task result
 28626 1448452649.11961: done sending task result
 28627 1448452649.12655: worker 0 has data to read
 28627 1448452649.13081: got a result from worker 0: <ansible.executor.task_result.TaskResult object at 0x7f181c8b06d0>
 28627 1448452649.13110: sending result: [u'host_task_failed', u'<ansible.executor.task_result.TaskResult object at 0x7f181c8b06d0>']
 28627 1448452649.13203: done sending result
 28619 1448452649.14120: got result from result worker: [u'host_task_failed', u'<ansible.executor.task_result.TaskResult object at 0x7f181c8d01d0>']
 28619 1448452649.14140: marking test-vm as failed
fatal: [test-vm]: FAILED! => {"failed": true, "msg": "ERROR! Timeout (12s) waiting for privilege escalation prompt: "}
 28619 1448452649.14189: no more pending results, returning what we have
 28619 1448452649.14199: results queue empty
 28619 1448452649.14208: getting the remaining hosts for this loop
 28619 1448452649.14218: done getting the remaining hosts for this loop
 28619 1448452649.14240: building list of next tasks for hosts
 28619 1448452649.14248: getting the next task for host test-vm
 28619 1448452649.14258: host test-vm is done iterating, returning
 28619 1448452649.14265: done building task lists
 28619 1448452649.14273: counting tasks in each state of execution
 28619 1448452649.14280: done counting tasks in each state of execution
 28619 1448452649.14288: all hosts are done, so returning None's for all hosts
 28619 1448452649.14296: done queuing things up, now waiting for results queue to drain
 28619 1448452649.14303: waiting for pending results...
 28619 1448452649.14310: no more pending results, returning what we have
 28619 1448452649.14321: out of hosts to run on

NO MORE HOSTS LEFT *************************************************************
 28619 1448452649.14337: running handlers
 28619 1448452649.14345: in VariableManager get_vars()
 28619 1448452649.14375: done with get_vars()
 28619 1448452649.14384: in VariableManager get_vars()
 28619 1448452649.14406: done with get_vars()
 28619 1448452649.14412: in VariableManager get_vars()
 28619 1448452649.14438: done with get_vars()
 28619 1448452649.14443: in VariableManager get_vars()
 28619 1448452649.14468: done with get_vars()
 28619 1448452649.14474: in VariableManager get_vars()
 28619 1448452649.14498: done with get_vars()
 28619 1448452649.14504: in VariableManager get_vars()
 28619 1448452649.14528: done with get_vars()
 28619 1448452649.14533: in VariableManager get_vars()
 28619 1448452649.14558: done with get_vars()
 28619 1448452649.14563: in VariableManager get_vars()
 28619 1448452649.14588: done with get_vars()
 28619 1448452649.14593: in VariableManager get_vars()
 28619 1448452649.14618: done with get_vars()
 28619 1448452649.14623: in VariableManager get_vars()
 28619 1448452649.14649: done with get_vars()
 28619 1448452649.14654: in VariableManager get_vars()
 28619 1448452649.14678: done with get_vars()
 28619 1448452649.14684: in VariableManager get_vars()
 28619 1448452649.14709: done with get_vars()
 28619 1448452649.14719: in VariableManager get_vars()
 28619 1448452649.14786: done with get_vars()
 28619 1448452649.15119: RUNNING CLEANUP

PLAY RECAP *********************************************************************
test-vm                  : ok=0    changed=0    unreachable=0    failed=1   
```

Can you confirm that's with current devel and not RC1, please? And can you show the playbook that you're using too?

Yes I am testing now against devel and here's my playbook.

```
---
- hosts:
    - test-vm
  become: yes
  tasks:
  - command: whoami
    register: whoami 
  - debug: msg="{{ whoami.stdout }}"
```

Works for me with devel and a cut-and-pasted copy of your playbook (against a host with NOPASSWD set in sudoers):

```
$ ANSIBLE_SSH_PIPELINING=1 ansible-playbook -ii p.yml

PLAY ***************************************************************************

TASK [setup] *******************************************************************
ok: [raven]

TASK [command] *****************************************************************
changed: [raven]

TASK [debug msg={{ whoami.stdout }}] *******************************************
ok: [raven] => {
    "changed": false, 
    "msg": "root"
}

PLAY RECAP *********************************************************************
raven                      : ok=3    changed=1    unreachable=0    failed=0   
```

I was using ansible.cfg to enable/disable pipelining using your method I noticed something else.
when ssh ControlPath exists there is no issue with pipelining enable but when there is no ControlPath it gives timeout.

To reproduce, 
file ~/.ssh/ansible-ssh-***\* does not exists
ANSIBLE_SSH_PIPELINING=1 ansible-playbook -ii p.yml
error

But,
ANSIBLE_SSH_PIPELINING=0 ansible-playbook -ii p.yml
file ~/.ssh/ansible-ssh-***\* exists
ANSIBLE_SSH_PIPELINING=1 ansible-playbook -ii p.yml
no error

Are you sure it's not just taking longer than 12s to establish the connection and run the command? Does it work if you add `-T60` to the command, for example?

I tried with 100 and it would timeout at 102s so I am sure it's not that.

Does this patch fix it for you? https://gist.github.com/amenonsen/8da2b110aacc70a1b014


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
@@ -457,12 +457,17 @@ def _run(self, cmd, in_data, sudoable=True):
                 tmp_stdout = tmp_stderr = ''
 
             # If we see a privilege escalation prompt, we send the password.
+            # (If we're expecting a prompt but the escalation succeeds, we
+            # didn't need the password and can carry on regardless.)
 
-            if states[state] == 'awaiting_prompt' and self._flags['become_prompt']:
-                display.debug('Sending become_pass in response to prompt')
-                stdin.write(self._play_context.become_pass + '\n')
-                self._flags['become_prompt'] = False
-                state += 1
+            if states[state] == 'awaiting_prompt':
+                if self._flags['become_prompt']:
+                    display.debug('Sending become_pass in response to prompt')
+                    stdin.write(self._play_context.become_pass + '\n')
+                    self._flags['become_prompt'] = False
+                    state += 1
+                elif self._flags['become_success']:
+                    state += 1
 
             # We've requested escalation (with or without a password), now we
             # wait for an error message or a successful escalation.


Test patch: