# task includes with facts

**URL:** <https://forum.ansible.com/t/task-includes-with-facts/15453>\
**Category:** Ansible Project\
**Created:** [June 12, 2014, 1:22pm UTC](https://forum.ansible.com/t/task-includes-with-facts/15453 "2014-06-12T13:22:29Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Oliver\_Heinz](https://avatars.discourse-cdn.com/v4/letter/o/db5fbb/32.png) [@Oliver\_Heinz](https://forum.ansible.com/u/Oliver_Heinz)\
**Post date:** [June 12, 2014, 1:22pm UTC](https://forum.ansible.com/t/task-includes-with-facts/15453/1 "2014-06-12T13:22:29Z")

</div>

Hi all,

I cannot use facts for include variables. I think it’s because the yaml syntax checker fails (as they don’t exits at that time):

My test play:

---

<div class="post-metadata">

**Author:** ![Serge\_van\_Ginderacht](https://avatars.discourse-cdn.com/v4/letter/s/b782af/32.png) [@Serge\_van\_Ginderacht](https://forum.ansible.com/u/Serge_van_Ginderacht)\
**Post date:** [June 12, 2014, 1:29pm UTC](https://forum.ansible.com/t/task-includes-with-facts/15453/2 "2014-06-12T13:29:17Z")

</div>

This is not possible, as the parsing of the playbooks happens before anything else.

The best practice here is to use conditionals on and variables within specific tasks.

---

<div class="post-metadata">

**Author:** ![Oliver\_Heinz](https://avatars.discourse-cdn.com/v4/letter/o/db5fbb/32.png) [@Oliver\_Heinz](https://forum.ansible.com/u/Oliver_Heinz)\
**Post date:** [June 12, 2014, 1:42pm UTC](https://forum.ansible.com/t/task-includes-with-facts/15453/3 "2014-06-12T13:42:25Z")

</div>

Using lt’s of conditionals get’s pretty messy - IMHO it would be nicer if it could be handled in seperate files.

I would love if syntax checks were a bit more relaxed here: If variables in an include statement cannot be replaced just print a warning instead of raising an error.

---

<div class="post-metadata">

**Author:** ![Serge\_van\_Ginderacht](https://avatars.discourse-cdn.com/v4/letter/s/b782af/32.png) [@Serge\_van\_Ginderacht](https://forum.ansible.com/u/Serge_van_Ginderacht)\
**Post date:** [June 12, 2014, 2:02pm UTC](https://forum.ansible.com/t/task-includes-with-facts/15453/4 "2014-06-12T14:02:11Z")

</div>

​You can assign conditionals next to task includes or roles though.​

---

<div class="post-metadata">

**Author:** ![Oliver\_Heinz](https://avatars.discourse-cdn.com/v4/letter/o/db5fbb/32.png) [@Oliver\_Heinz](https://forum.ansible.com/u/Oliver_Heinz)\
**Post date:** [June 12, 2014, 2:25pm UTC](https://forum.ansible.com/t/task-includes-with-facts/15453/5 "2014-06-12T14:25:27Z")

</div>

Thanks for pointing this out.

So  
tasks:

- include: “{{ansible\_distribution}}{{ansible\_distribution\_major\_version}}.yml”

would expand to

tasks:

- include: Debian6.yml  
when: ansible\_distribution == Debian AND ansible\_distribution\_major\_version == 6

- include: Debian7.yml  
when: ansible\_distribution == Debian AND ansible\_distribution\_major\_version == 7

- include: RedHat5.yml  
when: ansible\_distribution == RedHat AND ansible\_distribution\_major\_version == 5

- include: RedHat6.yml  
when: ansible\_distribution == RedHat AND ansible\_distribution\_major\_version == 6

[…]

This is definitely better than putting everything into one file. But I’d still like it much more when the single include + fact var worked - this is the way that is recommended for working with config templates/files so it feels somewhat wrong that it does not work with task includes.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [June 13, 2014, 2:37am UTC](https://forum.ansible.com/t/task-includes-with-facts/15453/6 "2014-06-13T02:37:09Z")

</div>

You can use “group\_by” to avoid repeated conditionals.

Select the hosts where something is true and apply roles/tasks to the dynamically created group.

---

<div class="post-metadata">

**Author:** ![Oliver\_Heinz](https://avatars.discourse-cdn.com/v4/letter/o/db5fbb/32.png) [@Oliver\_Heinz](https://forum.ansible.com/u/Oliver_Heinz)\
**Post date:** [June 13, 2014, 8:58am UTC](https://forum.ansible.com/t/task-includes-with-facts/15453/7 "2014-06-13T08:58:32Z")

</div>

Seperate roles for every flavor are exactly what I wan’t to avoid. We usually have different roles for different ansible\_os\_families but sometimes this is not granular enough.

We have the power to make decisions based on facts at runtime  
action: template src=apache2.conf.j2-{{ ansible\_lsb.codename }} dest={{ apache\_ConfigBase }}/apache2.conf

to create smart roles that don’t need repeated tasks with when statements for every flavor

But there is no smart way to decide which tasks to run based on facts - just because the YAML syntax checker raises an error because a variable is not defined (yet) and thus a play that is perfectly valid at runtime is considered faulty ☹ At least it would be great if that was configurable (fail/warn/ignore)

With the conditional includes we have a workaound for this shortcomming, so that we can reduce the conditionals to one per flavor. This is not great but sufficient - but as ansible is a great tool it is less than I expected 😉

thanks,  
Oliver

---

<div class="post-metadata">

**Author:** ![C\_Morgan\_Hamill](https://avatars.discourse-cdn.com/v4/letter/c/ebca7d/32.png) [@C\_Morgan\_Hamill](https://forum.ansible.com/u/C_Morgan_Hamill)\
**Post date:** [June 13, 2014, 1:02pm UTC](https://forum.ansible.com/t/task-includes-with-facts/15453/8 "2014-06-13T13:02:52Z")

</div>

Excerpts from Oliver Heinz's message of 2014-06-13 04:58:32 -0400:

> But there is no smart way to decide which tasks to run based on facts -  
> just because the YAML syntax checker raises an error because a variable is  
> not defined (yet) and thus a play that is perfectly valid at runtime is  
> considered faulty ☹ At least it would be great if that was configurable  
> (fail/warn/ignore)

My understanding here, having run into use cases for the same ability,  
is that Ansible has, as a conscious design goal, the principle that the  
task list should be reconstructable by as valid YAML without any  
run-time variable information. The idea being that one could parse  
a playbook programmatically without resorting to re-implementing the  
`ansible-playbook` script.

I \*believe\* this is part of the "infrastructure as data" idea that  
Michael likes to mention sometimes.

As a Unix partisan of the most obnoxious sort, I \*really\* like this: it  
reminds me of the "separate mechanism from policy" idea that's been  
part of the Unix style for decades, now.

Just sharing, as I think it's pretty awesome and worth the slight  
trade-off in functionality.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [June 13, 2014, 5:58pm UTC](https://forum.ansible.com/t/task-includes-with-facts/15453/9 "2014-06-13T17:58:15Z")

</div>

“But there is no smart way to decide which tasks to run based on facts - just because the YAML syntax checker raises an error because a variable is not defined (yet)”

when: foo is defined

it’s a thing

---

<div class="post-metadata">

**Author:** ![Oliver\_Heinz](https://avatars.discourse-cdn.com/v4/letter/o/db5fbb/32.png) [@Oliver\_Heinz](https://forum.ansible.com/u/Oliver_Heinz)\
**Post date:** [June 13, 2014, 7:15pm UTC](https://forum.ansible.com/t/task-includes-with-facts/15453/10 "2014-06-13T19:15:48Z")

</div>

> “But there is no smart way to decide which tasks to run based on facts - just because the YAML syntax checker raises an error because a variable is not defined (yet)”  
> when: foo is defined

When the variables used for the include have reasonable defaults the parser will not fail.So I defined some foo 😉

I defined those variables in role/defaults, because they have to loose in priotity to facts. But sadly defaults are not used when the syntax checker runs. If I rename the defaults dir to vars they are used and the syntax checker is satisfied [but for precedence reasons I obviously need defaults]  
=\> is this difference in behavior for role vars and defaults on purpose?

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [June 13, 2014, 8:49pm UTC](https://forum.ansible.com/t/task-includes-with-facts/15453/11 "2014-06-13T20:49:30Z")

</div>

I’m not sure what you mean when you say “syntax checker”.

Can you show the ansible command line you are running and also the output you are receiving?

---

<div class="post-metadata">

**Author:** ![Oliver\_Heinz](https://avatars.discourse-cdn.com/v4/letter/o/db5fbb/32.png) [@Oliver\_Heinz](https://forum.ansible.com/u/Oliver_Heinz)\
**Post date:** [June 13, 2014, 9:18pm UTC](https://forum.ansible.com/t/task-includes-with-facts/15453/12 "2014-06-13T21:18:53Z")

</div>

> I’m not sure what you mean when you say “syntax checker”.

Syntax checker is probably the wrong term, but before the play starts executing tasks all referenced yaml documents (roles, includes) seem to get parsed and if there is a syntax error in one of them you get an error message (or sometimes a helpful hint).

> Can you show the ansible command line you are running and also the output you are receiving?

playbooks/roles/test/

├── tasks  
│ ├── Debian7.yml  
│ └── main.yml  
└── vars  
└── main.yml

$ cat playbooks/roles/test/tasks/main.yml

---

<div class="post-metadata">

**Author:** ![Oliver\_Heinz](https://avatars.discourse-cdn.com/v4/letter/o/db5fbb/32.png) [@Oliver\_Heinz](https://forum.ansible.com/u/Oliver_Heinz)\
**Post date:** [June 13, 2014, 9:21pm UTC](https://forum.ansible.com/t/task-includes-with-facts/15453/13 "2014-06-13T21:21:51Z")

</div>

Sorry

$ tree -L 2 playbooks/roles/test/  
playbooks/roles/test/  
├── defaults  
│ └── main.yml  
└── tasks  
├── Debian7.yml  
└── main.yml

is the correct one before the move command.
