Repository: ansible/ansible

Issue:
Incorrect task name when using add_host and free strategy
##### SUMMARY

Using `add_host` in one play followed by the `free` strategy in another play will result in all tasks of the second play being named `add_host`.

##### ISSUE TYPE

Bug Report

##### COMPONENT NAME

add_host

##### ANSIBLE VERSION

```
ansible 2.7.0.dev0 (devel 479408330e) last updated 2018/08/10 10:13:14 (GMT -700)
  config file = None
  configured module search path = [u'/Users/mclay/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/mclay/code/mattclay/ansible/lib/ansible
  executable location = /Users/mclay/code/mattclay/ansible/bin/ansible
  python version = 2.7.14 (default, Mar 22 2018, 11:39:16) [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)]
```

##### CONFIGURATION

None

##### OS / ENVIRONMENT

N/A

##### STEPS TO REPRODUCE

main.yaml

```yaml
- hosts: localhost
  gather_facts: no
  tasks:
    - add_host:
        name: one
        ansible_connection: local

- hosts: one
  gather_facts: no
  strategy: free
  tasks:
    - debug: msg='hello'
```

Command: `ansible-playbook main.yaml`

##### EXPECTED RESULTS

```
PLAY [localhost] ***********************************************************************************************************************************************************************************

TASK [add_host] ************************************************************************************************************************************************************************************
changed: [localhost]

PLAY [one] *****************************************************************************************************************************************************************************************

TASK [debug] ***************************************************************************************************************************************************************************************
ok: [one] => {
    "msg": "hello"
}

PLAY RECAP *****************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0   
one                        : ok=1    changed=0    unreachable=0    failed=0   
```

##### ACTUAL RESULTS

```
PLAY [localhost] ***********************************************************************************************************************************************************************************

TASK [add_host] ************************************************************************************************************************************************************************************
changed: [localhost]

PLAY [one] *****************************************************************************************************************************************************************************************

TASK [add_host] ************************************************************************************************************************************************************************************
ok: [one] => {
    "msg": "hello"
}

PLAY RECAP *****************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0   
one                        : ok=1    changed=0    unreachable=0    failed=0   
```

Notice that the second task is named `TASK [add_host]` instead of `TASK [debug]` when using the `free` strategy. Avoiding use of the `free` strategy, or `add_host` will avoid the issue.


Discussion:
At a glance, this sounds like maybe a play_iterator bug; I notice this particular sample includes only `bypass_host_loop` actions.
This was introduced in 9c5d40ff152a8a94dc226735ce43593ebbb10104

It seems to be related to the special casing of `free` and tracking `self._last_task_name`


cc @agaffney
The `free` strategy is such a PITA when working on stdout callback plugins.

Resolving patch:
diff --git a/lib/ansible/plugins/callback/default.py b/lib/ansible/plugins/callback/default.py
--- a/lib/ansible/plugins/callback/default.py
+++ b/lib/ansible/plugins/callback/default.py
@@ -167,7 +167,11 @@ def v2_playbook_on_no_hosts_remaining(self):
     def v2_playbook_on_task_start(self, task, is_conditional):
         # Preserve task name, as all vars may not be available for templating
         # when we need it later
-        if self._play.strategy != 'free':
+        if self._play.strategy == 'free':
+            # Explicitly set to None for strategy 'free' to account for any cached
+            # task title from a previous non-free play
+            self._last_task_name = None
+        else:
             self._last_task_name = task.get_name().strip()
 
             # Display the task banner immediately if we're not doing any filtering based on task result


Test patch: