# Changes to when and conditionals in Ansible 2.2

**URL:** <https://forum.ansible.com/t/changes-to-when-and-conditionals-in-ansible-2-2/22949>\
**Category:** Ansible Project\
**Created:** [November 2, 2016, 9:37pm UTC](https://forum.ansible.com/t/changes-to-when-and-conditionals-in-ansible-2-2/22949 "2016-11-02T21:37:10Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dan\_Lang](https://avatars.discourse-cdn.com/v4/letter/d/3e96dc/32.png) [@Dan\_Lang](https://forum.ansible.com/u/Dan_Lang)\
**Post date:** [November 2, 2016, 9:37pm UTC](https://forum.ansible.com/t/changes-to-when-and-conditionals-in-ansible-2-2/22949/1 "2016-11-02T21:37:10Z")

</div>

I’m testing existing roles and playbooks against Ansible 2.2, and I’ve noticed that several roles that I have written that take advantage of “when: variable is defined” or “when: variable is undefined” in tasks no longer work. This happens when a variable is used from a previous task, but is empty because maybe the results were empty. Here is an example:

> - name: Find existing rules  
> find: path=/etc/software/rules/  
> register: existing\_rules
> - name: Clean rules  
> file: path={{ item }} state=absent  
> with\_items: “{{ existing\_rules.files | map(attribute=‘path’) | list }}”  
> when: existing\_rules is defined

In this case, there were no existing files, so the variable is empty and I would expect this **Clean rules** task to be skipped, but instead Ansible errors with something like

> FAILED! =\> {“failed”: true, “msg”: “‘dict object’ has no attribute ‘files’”}

What are the options then to allow for this sort of conditional logic? This definitely worked in Ansible 2.1, but I don’t recall if any DEPRECATED warnings were given.

---

<div class="post-metadata">

**Author:** ![sivel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/sivel/32/1198_2.png) [@sivel](https://forum.ansible.com/u/sivel)\
**Post date:** [November 2, 2016, 9:43pm UTC](https://forum.ansible.com/t/changes-to-when-and-conditionals-in-ansible-2-2/22949/2 "2016-11-02T21:43:28Z")

</div>

In 2.1 this would have been a deprecation warning. What you need is something like:

with\_items: “{{ existing\_rules.files | default() | map(attribute=‘path’) | list }}”

That gives existing\_rules.files a default of an empty list.

Also off note here, is that `when` statements are processed for each iteration of the with\_items loop, and not before the with\_items. So your with\_items needs to process correctly all the time. As such, you could remove `when` statement altogether as it isn’t doing what you wanted it to do.

---

<div class="post-metadata">

**Author:** ![Dan\_Lang](https://avatars.discourse-cdn.com/v4/letter/d/3e96dc/32.png) [@Dan\_Lang](https://forum.ansible.com/u/Dan_Lang)\
**Post date:** [November 3, 2016, 12:41am UTC](https://forum.ansible.com/t/changes-to-when-and-conditionals-in-ansible-2-2/22949/3 "2016-11-03T00:41:21Z")

</div>

Thanks for the info Matt. The Ansible docs, [http://docs.ansible.com/ansible/playbooks\_conditionals.html](http://docs.ansible.com/ansible/playbooks_conditionals.html), indicate this is should work as before. Specifically,

> If a required variable has not been set, you can skip or fail using Jinja2’s test. For example:
> 
> ```auto
> tasks:
> - shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
> when: foo is defined
> 
> - fail: msg="Bailing out. this play requires 'bar'"
> when: bar is undefined
> 
> ```
> 
> This is especially useful in combination with the conditional import of vars files (see below).

Do you know where this behavior is documented? I’d like to update the docs and submit a PR.

---

<div class="post-metadata">

**Author:** ![sivel](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/sivel/32/1198_2.png) [@sivel](https://forum.ansible.com/u/sivel)\
**Post date:** [November 3, 2016, 1:54am UTC](https://forum.ansible.com/t/changes-to-when-and-conditionals-in-ansible-2-2/22949/4 "2016-11-03T01:54:04Z")

</div>

If you read a little further down, under the “Loops and Conditionals”[1] this information is present:

> Combining when with with\_items (see Loops), be aware that the when statement is processed separately for each item… If you need to skip the whole task depending on the loop variable being defined, used the |default filter to provide an empty iterator

[1] [http://docs.ansible.com/ansible/playbooks\_conditionals.html#loops-and-conditionals](http://docs.ansible.com/ansible/playbooks_conditionals.html#loops-and-conditionals)

---

<div class="post-metadata">

**Author:** ![Josh\_Smift1](https://avatars.discourse-cdn.com/v4/letter/j/bcef8e/32.png) [@Josh\_Smift1](https://forum.ansible.com/u/Josh_Smift1)\
**Post date:** [November 3, 2016, 1:53pm UTC](https://forum.ansible.com/t/changes-to-when-and-conditionals-in-ansible-2-2/22949/5 "2016-11-03T13:53:40Z")

</div>

> In this case, there were no existing files, so the variable is empty  
> and I would expect this \*Clean rules\* task to be skipped

Hmm, isn't the real problem that after the first task, exiting\_rules  
\*isn't\* undefined any more?

Add a debug task (- debug: var=existing\_rules), and I see things like

&nbsp;&nbsp;TASK [debug] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
&nbsp;&nbsp;ok: [localhost] =\> {  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"existing\_rules": {  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"changed": false,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"examined": 0,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"files": ,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"matched": 0,  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"msg": ""  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}  
&nbsp;&nbsp;}

So I think the "Clean rules" tries to do stuff because "when:  
existing\_rules is defined" evaluates to true.

> but instead Ansible errors with something like
> 
> \> FAILED! =\> {"failed": true, "msg": "'dict object' has no attribute  
> \> 'files'"}

Hmm, that's not what I get; in either 2.1 or 2.2, I see

&nbsp;&nbsp;TASK [Clean rules] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

and then no further output -- which makes sense, because existing\_rules is  
defined, and has a zero-length 'files' list. I'm not sure why you're  
getting the error you're getting.

Here's my (slightly modified) list of tasks, just to be sure:

&nbsp;&nbsp;&nbsp;&nbsp;- name: Find existing rules  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;find: path=/tmp/foo  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;register: existing\_rules

&nbsp;&nbsp;&nbsp;&nbsp;- debug: var=existing\_rules

&nbsp;&nbsp;&nbsp;&nbsp;- name: Clean rules  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;debug: msg="{{ item }}"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;with\_items: "{{ existing\_rules.files | map(attribute='path') | list }}"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when: existing\_rules is defined

/tmp/foo is an empty (but existent) directory.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-Josh (jbs@care.com)

(apologies for the automatic corporate disclaimer that follows)

This email is intended for the person(s) to whom it is addressed and may contain information that is PRIVILEGED or CONFIDENTIAL. Any unauthorized use, distribution, copying, or disclosure by any person other than the addressee(s) is strictly prohibited. If you have received this email in error, please notify the sender immediately by return email and delete the message and any attachments from your system.
