Undefined variables and loops

30 views
Skip to first unread message

Guy Knights

unread,
May 24, 2016, 1:52:24 PM5/24/16
to ansible...@googlegroups.com
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

Matt Martz

unread,
May 24, 2016, 1:58:57 PM5/24/16
to ansible...@googlegroups.com
`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.

--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
To post to this group, send email to ansible...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ansible-project/CANNH9mvCU6x1kgZa%2Bt3Zu4ZO%2B6n4%2BoNAd8HM99tbz-D7SWa3kw%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.



--
Matt Martz
@sivel
sivel.net
Reply all
Reply to author
Forward
0 new messages