# ansible\_facts and with\_items don't play nicely

**URL:** <https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147>\
**Category:** Ansible Project\
**Created:** [December 18, 2012, 5:55pm UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147 "2012-12-18T17:55:28Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![Nick](https://avatars.discourse-cdn.com/v4/letter/n/f9ae1b/32.png) [@Nick](https://forum.ansible.com/u/Nick)\
**Post date:** [December 18, 2012, 5:55pm UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/1 "2012-12-18T17:55:28Z")

</div>

Hi,

I'm writing a module which sets facts via the ansible\_facts. (Actually, it's an action plugin, but that makes no difference, I see the same thing either way.)

When used in a task, it works fine:

&nbsp;&nbsp;- name: my module  
&nbsp;&nbsp;&nbsp;&nbsp;action: mymodule $myparam

When used with "with\_items", apparently nothing gets set:

&nbsp;&nbsp;- name: my module  
&nbsp;&nbsp;&nbsp;&nbsp;action: mymodule $item  
with\_items:  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- one  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;- two

Delving in the source it seems that in that case the results hash for each invocation of the module is packaged into an array, and \*that\* is the result value returned. The code which then checks for ansible\_facts looks and finds nothing, so nothing gets set.

Is that by design? Or is it a bug?

N

---

<div class="post-metadata">

**Author:** ![Nick](https://avatars.discourse-cdn.com/v4/letter/n/f9ae1b/32.png) [@Nick](https://forum.ansible.com/u/Nick)\
**Post date:** [December 19, 2012, 12:11am UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/2 "2012-12-19T00:11:20Z")

</div>

> Is that by design? Or is it a bug?

Excuse me, I've answered my own question - checking git-blame, apparently this  
\*is\* by design. Michael Haan writes in commit 19fc8e:

> Things that happen inside multiprocessing shouldn't make side effects, ergo  
> append ansible\_facts only  
> in playbook code.  
> &nbsp;&nbsp;&nbsp;&nbsp;  
> This technically means with\_items calls can't continuously add facts I guess,  
> but I can't see anyone  
> ever trying that.

&nbsp;&nbsp;[https://github.com/gdub/ansible/commit/19fc8eea807547f9945cf1b29a36f2061518ee6d](https://github.com/gdub/ansible/commit/19fc8eea807547f9945cf1b29a36f2061518ee6d)

Speaking personally, it doesn't seem especially unreasonable to expect  
ansible\_facts to be respected in an action with\_items, but even so, maybe  
Ansible should warn when it ignores ansible\_facts like this?

(I won't elaborate on my use case just now unless case requested - it's late  
and hard to explain these things briefly at the best of times.)

N

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@Michael\_DeHaan](https://forum.ansible.com/u/Michael_DeHaan)\
**Post date:** [December 19, 2012, 1:23am UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/3 "2012-12-19T01:23:45Z")

</div>

> > Is that by design? Or is it a bug?
> 
> Excuse me, I've answered my own question - checking git-blame, apparently this  
> \*is\* by design. Michael Haan writes in commit 19fc8e:

I don't know this person.

> > Things that happen inside multiprocessing shouldn't make side effects, ergo  
> > append ansible\_facts only  
> > in playbook code.
> > 
> > This technically means with\_items calls can't continuously add facts I guess,  
> > but I can't see anyone  
> > ever trying that.
> 
> &nbsp;&nbsp;[https://github.com/gdub/ansible/commit/19fc8eea807547f9945cf1b29a36f2061518ee6d](https://github.com/gdub/ansible/commit/19fc8eea807547f9945cf1b29a36f2061518ee6d)
> 
> Speaking personally, it doesn't seem especially unreasonable to expect  
> ansible\_facts to be respected in an action with\_items, but even so, maybe  
> Ansible should warn when it ignores ansible\_facts like this?

I never said it was unreasonable, it was just not convenient at the time.

What this says is that facts are loaded into the main namespace  
\*AFTER\* they get back from the multiprocessing code. In doing this,  
we must set whatever facts come as the result of the task, which at  
architectural levels is not 10 tasks, one for each item, but one task.

Thus what you see in the first changeset of that patch -- would have  
to somehow merge things in some sort of magic way.

It's not true that with\_items can't set facts -- but it is true that  
the last one will win.

Facts are a flat namespace.

I'd have to see the source of your module to really know what you are  
doing and to offer any suggestions, but you haven't shown me enough  
quite yet.

---

<div class="post-metadata">

**Author:** ![Brian\_Coca1](https://avatars.discourse-cdn.com/v4/letter/b/278dde/32.png) [@Brian\_Coca1](https://forum.ansible.com/u/Brian_Coca1)\
**Post date:** [December 19, 2012, 1:31am UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/4 "2012-12-19T01:31:33Z")

</div>

Python doesn’t have good ways to merge dictionaries

Brian Coca

---

<div class="post-metadata">

**Author:** ![Dag\_Wieers](https://avatars.discourse-cdn.com/v4/letter/d/45deac/32.png) [@Dag\_Wieers](https://forum.ansible.com/u/Dag_Wieers)\
**Post date:** [December 19, 2012, 9:46am UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/5 "2012-12-19T09:46:30Z")

</div>

In light of our network\_facts module (which returns DNS and network facts based on hostname/ip-address) I was looking into a way to set facts for more than one interface/ip-address using with\_items.

I was hoping for one of either solution:

&nbsp;&nbsp;- Influence the namespace by item, eg. network\_fqdn would become  
&nbsp;&nbsp;&nbsp;&nbsp;network\_${item}\_fqdn (could be problematic if $item is an ip-address)

&nbsp;&nbsp;- Expand ansible\_facts to merge and return dictionaries using item as  
&nbsp;&nbsp;&nbsp;&nbsp;key.

Another option was to do something similar as the yum module is doing, and have a single run with all items collated.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@Michael\_DeHaan](https://forum.ansible.com/u/Michael_DeHaan)\
**Post date:** [December 19, 2012, 12:44pm UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/6 "2012-12-19T12:44:28Z")

</div>

It's a little gross to indicate this behavior is desired without  
having a plugin, but we \*could\* parse the module to figure this out.

So the yum/apt modules would have some string in them like  
"WITH\_ITEMS\_OPTIMIZED=True" and we could do a re.search  
for that (and various spacing variations) when deciding to execute the  
module.

Scary, but it would work and avoid requiring changes to the core  
runner/\_\_init\_\_.py

Something like that, perhaps? I want to avoid a config file as  
module source should be self contained.

---

<div class="post-metadata">

**Author:** ![Nick](https://avatars.discourse-cdn.com/v4/letter/n/f9ae1b/32.png) [@Nick](https://forum.ansible.com/u/Nick)\
**Post date:** [December 19, 2012, 11:51pm UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/7 "2012-12-19T23:51:19Z")

</div>

Mr Haan is of course yet another alter-ego of Saint Benedict the Splenetic, the patron saint of culpable old gits. Understood, and I don’t claim you or Mr Haan said so. Also understood. It’s an experiment, but it boils down to being a means for (giving the illusion of) appending values to pre-existing var lists (or perhaps dictionaries). For example, given a task like this: Then if there is a list defined at ${some.name}, then it has the value of ${some\_value} appended to it. If not, there should be an error, because I don’t want to allow new values to silently pop up just anywhere. I’d also like to be able to do this: …and append a number of items to said list. As for why I’d want to do that, an example usage would be to define a var structure with a list in it, perhaps like this: backup: when: … to\_where: … what: - /etc - /home …Which could be used by a task somewhere to generate the config for the backup system. When I add more plays for other systems to the playbook, I could of course append the paths for their precious data to the “what” list. The problem with this is that it would require me to edit at least two places to plumb each system in to my playbook, and subsequent refactoring would become error-prone (because the paths may become mismatched). Alternatively I could try and make my systems’ datastructures conform to a scheme that can be iterated over from a template in the backup play. This seems likely to be inconvenient at best, and also prone to errors resulting from mismatched paths (if they paths are simply listed in the wrong place, nothing happens, but I may not realise things aren’t getting backed up). If however, plays can invoke such an “appendvar” module to add paths they know need backing up to ${backup.include}, this seems to make life easier, allowing more modularity with less duplication and cross-correlation. Equally importantly, if ${backup.include} isn’t there, I find out quickly when I see the error. It’s not proving as easy to implement as I’d like, but I haven’t found anything I’d consider a better solution yet, so I’ve been trying to doggedly persevere with it. I’d be happy if the last invoked won, assuming each invocation could amend the result of the one before. Cheers, N

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@Michael\_DeHaan](https://forum.ansible.com/u/Michael_DeHaan)\
**Post date:** [December 20, 2012, 1:02pm UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/8 "2012-12-20T13:02:52Z")

</div>

> I'd be happy if the last with\_items invoked won, assuming each invocation  
> could amend the result of the one before.

Those two statements seem to be opposites.

---

<div class="post-metadata">

**Author:** ![Nick](https://avatars.discourse-cdn.com/v4/letter/n/f9ae1b/32.png) [@Nick](https://forum.ansible.com/u/Nick)\
**Post date:** [December 20, 2012, 4:25pm UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/9 "2012-12-20T16:25:11Z")

</div>

Well, not in the sense I mean it. Say we have this: when item = one, list is amended to to [blah, one] when item = two, list is amended to [blah, one, two] when item = three, list is amended to [blah, one, two, three] The last one wins, but since it is amending the value, the previous alterations are preserved. The order is significant too, of course. Since I’m writing an action plug-in in Python, I can inspect the current state of the ‘inject’ python dict, and return top-level key replacement which “amends” the previous state by clobbering the referenced data-structure with a near-identical one with only the desired changes. Not the nicest or most efficient way of amending things, but I don’t think I have any alternative. N

---

<div class="post-metadata">

**Author:** ![Brian\_Coca1](https://avatars.discourse-cdn.com/v4/letter/b/278dde/32.png) [@Brian\_Coca1](https://forum.ansible.com/u/Brian_Coca1)\
**Post date:** [December 20, 2012, 5:02pm UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/10 "2012-12-20T17:02:09Z")

</div>

That would force the task to be run synchronously, one item at a time.

---

<div class="post-metadata">

**Author:** ![Nick](https://avatars.discourse-cdn.com/v4/letter/n/f9ae1b/32.png) [@Nick](https://forum.ansible.com/u/Nick)\
**Post date:** [December 20, 2012, 10:55pm UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/11 "2012-12-20T22:55:09Z")

</div>

A nominally working draft of the appendvar.py action plug-in described in the  
parent thread. Thanks due to daniel\_hozac for his help on IRC.

&nbsp;&nbsp;&nbsp;&nbsp;[https://gist.github.com/4349222](https://gist.github.com/4349222)

This version includes a workaround for the ansible\_facts/with\_items problem:

- action: appendvar list=some.list item=${some\_datastructure} # appends one  
item to some.list

- action: appendvar list=some.list items=${some\_list\_of\_datastructures} #  
appends many items to some.list

(Note this is the first Python code I've written to date. so it may be peculiar.)

N

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@Michael\_DeHaan](https://forum.ansible.com/u/Michael_DeHaan)\
**Post date:** [December 21, 2012, 12:54pm UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/12 "2012-12-21T12:54:12Z")

</div>

I'm not going to include this in core because it's rather uncertain to  
most people as to why you'd ever need it.

Thankfully, this is what plugins were attended to accomplish, so you  
can still use this yourself.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@Michael\_DeHaan](https://forum.ansible.com/u/Michael_DeHaan)\
**Post date:** [December 21, 2012, 12:59pm UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/13 "2012-12-21T12:59:43Z")

</div>

I've written code to do this at least 57 times 🙂

I don't think ansible needs this though.

If the OP is writing his own action plugin, he's good to go.

---

<div class="post-metadata">

**Author:** ![Nick](https://avatars.discourse-cdn.com/v4/letter/n/f9ae1b/32.png) [@Nick](https://forum.ansible.com/u/Nick)\
**Post date:** [December 21, 2012, 10:34pm UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/14 "2012-12-21T22:34:58Z")

</div>

That is as I expected, so no problem there.

I would be very pleased if you could show me a more idiomatic way to do what I  
am trying to do, but I can only guess that either you're entirely baffled by  
what I'm proposing or there are no examples you can point to... can you clarify?

N

---

<div class="post-metadata">

**Author:** ![Nick](https://avatars.discourse-cdn.com/v4/letter/n/f9ae1b/32.png) [@Nick](https://forum.ansible.com/u/Nick)\
**Post date:** [December 21, 2012, 10:37pm UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/15 "2012-12-21T22:37:05Z")

</div>

Yes, exactly my point. I don't know of any guarantees with\_items makes either  
way, but it seems to run synchronously. If that changed, this case would go  
awry, and possibly other unrelated cases too.

N

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan](https://avatars.discourse-cdn.com/v4/letter/m/c4cdca/32.png) [@Michael\_DeHaan](https://forum.ansible.com/u/Michael_DeHaan)\
**Post date:** [December 23, 2012, 1:54pm UTC](https://forum.ansible.com/t/ansible-facts-and-with-items-dont-play-nicely/12147/16 "2012-12-23T13:54:54Z")

</div>

> > I'm not going to include this in core because it's rather uncertain to  
> > most people as to why you'd ever need it.
> 
> That is as I expected, so no problem there.
> 
> I would be very pleased if you could show me a more idiomatic way to do what I  
> am trying to do, but I can only guess that either you're entirely baffled by  
> what I'm proposing or there are no examples you can point to... can you clarify?

I understand exactly what you are doing, I just think it's not  
something but 1% of anyone needs to do, so it does not belong in core.
