Repository: ansible/ansible

Issue:
Dynamically excluded tasks are still evaluated
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
include_tasks

##### ANSIBLE VERSION
```
ansible-playbook 2.5.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/felix/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/site-packages/ansible-2.5.0-py2.7.egg/ansible
  executable location = /usr/bin/ansible-playbook
  python version = 2.7.13 (default, May 10 2017, 20:04:28) [GCC 6.3.1 20161221 (Red Hat 6.3.1-1)]
```

##### CONFIGURATION
```
ANSIBLE_NOCOWS(env: ANSIBLE_NOCOWS) = True
PERSISTENT_CONNECT_TIMEOUT(/etc/ansible/ansible.cfg) = 30
```

##### OS / ENVIRONMENT
Fedora 24, running local playbook

##### SUMMARY
The include_tasks feature does not behave as expected. Particularly the 'dynamic' aspect that is emphasized in the documentation does not work.
Executing the playbook.yml posted below:
```
ansible-playbook playbook.yml
```
It seems to me that the pre 2.4 behavior is still present - the condition is simply applied to every single included task, instead of dynamically skipping the include due to the failing conditional.
The documentation [here](http://docs.ansible.com/ansible/latest/playbooks_reuse.html) suggests a different behavior.

##### 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.
-->

*playbook.yml*:
```yaml
---
- hosts: 127.0.0.1
  gather_facts: no

  tasks:
  
  - name: "Include Task"
    include_tasks: include.yml
    when: False
```
*include.yml*:
```yaml
- name: "Include 1"
  debug:
    msg: "Include 1"

- name: "Include 2"
  debug:
    msg: "Include 2"

- name: "Include 3"
  debug:
    msg: "Include 3"
```
<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
Expected something along those lines:

```

PLAY [127.0.0.1] *********************************************************************************************************************************************

TASK [Include Task] *********************************************************************************************************************************************
skipping: [127.0.0.1]

PLAY RECAP ***************************************************************************************************************************************************
127.0.0.1                  : ok=0    changed=0    unreachable=0    failed=0   

```

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```

PLAY [127.0.0.1] *********************************************************************************************************************************************

TASK [Include 1] *********************************************************************************************************************************************
skipping: [127.0.0.1]

TASK [Include 2] *********************************************************************************************************************************************
skipping: [127.0.0.1]

TASK [Include 3] *********************************************************************************************************************************************
skipping: [127.0.0.1]

PLAY RECAP ***************************************************************************************************************************************************
127.0.0.1                  : ok=0    changed=0    unreachable=0    failed=0   

```



Discussion:
You seem to be mixing terms here. You reference `include_tasks` which is the dynamic version, however your playbook is using `import_tasks` which is the static version.
I'm sorry, I copied the playbook in the wrong version. I tried `import_tasks` to compare the two.
I am actually referring to the dynamic version, `include_tasks`. I have updated the example playbook accordingly.
As a side note: both `import_tasks` and `include_tasks` produce the exact output in this example,
which also highlights the issue.
Ok, it seems this was broken in e609618274db6a7e3c273abde457f53de8c9976c

Since e609618274db6a7e3c273abde457f53de8c9976c `include_tasks` and `import_tasks` both seem to work as `import_tasks` was designed to.

cc @jimi-c 
An updated playbook that uses both:

```
---
- hosts: localhost
  gather_facts: no
  tasks:
  - name: "Include Task"
    include_tasks: include.yml
    when: False

  - name: "Import Task"
    import_tasks: include.yml
    when: False
```
I've also put together a gist to show this behavior:

https://gist.github.com/sivel/a49acdc41faa609274ed11141b6e99eb
One further note: The commit has also been cherry-picked to the stable-2.4 branch, which is where I noticed it initially:

https://github.com/ansible/ansible/commit/ef96329ae2279b3480261b8b737a8d41da663e5e

Resolving patch:
diff --git a/lib/ansible/playbook/helpers.py b/lib/ansible/playbook/helpers.py
--- a/lib/ansible/playbook/helpers.py
+++ b/lib/ansible/playbook/helpers.py
@@ -133,8 +133,9 @@ def load_list_of_tasks(ds, play, block=None, role=None, task_include=None, use_h
                 # check to see if this include is dynamic or static:
                 # 1. the user has set the 'static' option to false or true
                 # 2. one of the appropriate config options was set
-                is_static = False
-                if 'import_tasks' in task_ds:
+                if 'include_tasks' in task_ds:
+                    is_static = False
+                elif 'import_tasks' in task_ds:
                     is_static = True
                 elif t.static is not None:
                     display.deprecated("The use of 'static' has been deprecated. "


Test patch: