task includes with facts

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:

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.

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.

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

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.

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.

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 :frowning: 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 :wink:

thanks,
Oliver

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 :frowning: 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.

“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

“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 :wink:

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?

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?

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

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.