Issue 1:
ISSUE TYPE

Bug Report

COMPONENT NAME

role inclusion

ANSIBLE VERSION

ansible 2.4.2.0
config file = /home/user/.ansible.cfg
configured module search path = [u'/home/user/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /home/user/ansible/lib/python2.7/site-packages/ansible
executable location = /home/user/ansible/bin/ansible
python version = 2.7.5 (default, Aug 2 2016, 04:20:16) [GCC 4.8.5 20150623 (Red Hat 4.8.5-4)]

CONFIGURATION

ANSIBLE_SSH_ARGS(/home/user/.ansible.cfg) = -o Protocol=2

OS / ENVIRONMENT

Manager host is RHEL 7.3

SUMMARY

Playbook has a list of roles to execute. If a role is repeated multiple times in the list, it is only executed the first time. If I use dict syntax to invoke the role, and add parameters to the role so that the duplicate invocations are slightly different, then the role gets executed as expected provided there are no exact duplicates in the role arguments.

STEPS TO REPRODUCE

Create a role that just prints some debug output. Sample role below.

Invoke the role multiple times from a play

The role only executes once.

Edit the playbook to disambiguate the role invocations (see WORKAROUND below)

The role now executes once for each unique invocation

Sample role used in test:

$ cat roles/do-nothing/tasks/main.yml

---

- name: do nothing
debug:
var: ansible_version

Sample playbook used to reproduce:

$ cat nothing1.yml

---

- hosts: "{{ host_to_upgrade }}"

gather_facts: false

roles:
- do-nothing
- do-nothing
- do-nothing

EXPECTED RESULTS

We should see the role "do-nothing" get run three times.

ACTUAL RESULTS

$ ansible-playbook -i ../hosts.test -e host_to_upgrade=njwdev1 nothing1.yml

PLAY [njwdev1] *****************************************************************

TASK [do-nothing : do nothing] *************************************************
ok: [njwdev1] => {
"ansible_version": {
"full": "2.4.2.0",
"major": 2,
"minor": 4,
"revision": 2,
"string": "2.4.2.0"
}
}

PLAY RECAP *********************************************************************
njwdev1 : ok=1 changed=0 unreachable=0 failed=0

WORKAROUND

This playbook shows how I'm working around the problem:

---

- hosts: "{{ host_to_upgrade }}"

gather_facts: false

roles:
- do-nothing
- { role: do-nothing, disambiguate_kludge: 1 }
- { role: do-nothing, disambiguate_kludge: 2 }

Note: If "disambiguate_kludge" is set to "1" instead of "2" in the 3rd role line above, then the role only executes twice.

Issue 2:
Issue Type:

Bug Report

Ansible Version:

$ ansible --version

ansible 1.7.2

Environment:

MacOS (also occurs on Ubuntu 14.04)

Summary:

ssh logins that require sudo passwords can hang indefinitely.

Steps To Reproduce:

I think the bug could be be reproduced if you enable sudo passwords and change sudo to a program that runs 'sleep 10' before it executes. Then run a playbook with the "--ask-sudo" parameter with that machine in the inventory.

Here is what I think is happening:

Ansible attempts to ssh into a machine.

Ansible successfully logs in and attempts to run 'sudo'.

sudo takes a while and requires a password to be entered.

Ansible does a select() on the read socket.

The select() times out after 10 seconds. Ansible waits for the SSH process to terminate (from ansible/runner/connection_plugins/ssh.py):

if not rfd:
# timeout. wrap up process communication
stdout = p.communicate()
raise errors.AnsibleError('ssh connection error waiting for sudo or su password prompt')

However, since Ansible is logged in and sudo is running, the process never terminates. communicate() gets stuck.

Essentially, I think this is a corner case where the ssh login succeeds, but the time it takes for sudo to execute and ask for a password exceeds the timeout. Since the ssh session was successful, the ssh process will never return, causing Ansible to hang indefinitely.

I verified this was happening by adding a 'continue', here:

if not rfd:
continue
# timeout. wrap up process communication
stdout = p.communicate()

This worked--essentially a short time later, the select() returned successfully, and Ansible functioned well. To confirm this, I added some debug statements using time.time(). Here is what I saw:

t = 0: start of first select()

t = 10.000742: timeout occurs

t = 10.000874: second select() returns successfully

How to fix this? Ideally, we would have some way of knowing that the ssh session successfully logged in but was waiting for sudo. I don't think there is a foolproof way of knowing this.

In any case, communicate() should have a timeout, so that if ssh fails to terminate, we either terminate the ssh process or run select() again just to be sure. There are some ideas here for how to implement a timeout:

http://stackoverflow.com/questions/1191374/subprocess-with-timeout

For now, I've worked around the problem by changing timeout = 20, but I think the code still needs to prevent communicate() from getting stuck.

Expected Results:

ssh logins and sudo executes fine

Actual Results:

ssh process never returns and causes Ansible to get stuck

I think a similar issue was reported in issue #8058.