Undefined variables and loops

I’ve run into a deprecation error related to an undefined variable in a with_items loop. The task definition is below:

name: template syslog config snippets
template:
src: “{{ item }}.conf.j2”
dest: “/etc/rsyslog.d/{{ item }}.conf”
mode: 0644
with_items: “{{ syslog.snippets|default(1) }}”
when: syslog is defined
notify:

  • restart rsyslog

The “when” clause was originally ‘when: syslog is defined and syslog.snippets is defined’, but I was getting the deprecation warning for both syslog and syslog.snippets and I found various threads which explained the issue with when clauses and loops, so I adjusted it as suggested. However, because the list I’m referencing is actually a value of a dict key, I still need to test that ‘syslog’ is defined, but I’m still getting the deprecation warning about ‘syslog’ not being defined.

[DEPRECATION WARNING]: Skipping task due to undefined Error, in the future this will be a fatal error.: ‘syslog’ is undefined.
This
feature will be removed in a future release.

Is there a way to test for this effectively, or is my only option to define a ‘fake’ syslog var for servers that don’t have it, so that it passes the test for syslog, but not syslog.snippets?

Thanks,
Guy

when statements are not evaluated before the task starts. They are evaluated for each iteration of the loop. So by the time it is evaluated, ansible is already trying to loop the undefined variable.

In 1.9 this was silently ignored, and the task was skipped.

In 2.0 we added the deprecation notice.

The correct way is to ensure that with_items gets an iterable variable. We recommend the use of the |default filter.

The problem becomes more difficult if the variable is multiple layers, such as syslog.snippets, so there are a few ways to do this:

with_items: “{{ (syslog|default(dict()))[‘snippets’]|default() }}”

Or potentially with using ‘combine’, such as:

with_items: “{{ (syslog|combine(dict(snippets=)))[‘snippets’] }}”

Both are a little complicated.

Other options are to always define this in a way that allows the task to not have complicated loop data. Maybe even specifying it as a group_vars or similar.

Or perhaps to use an set_fact task to do some of the heavy lifting before you try to use it.

One last option, use less complex variables.