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:
- name: my module
action: mymodule $myparam
When used with "with_items", apparently nothing gets set:
- name: my module
action: mymodule $item
with_items:
- one
- 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.
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.)
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.
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:
- Influence the namespace by item, eg. network_fqdn would become
network_${item}_fqdn (could be problematic if $item is an ip-address)
- Expand ansible_facts to merge and return dictionaries using item as
key.
Another option was to do something similar as the yum module is doing, and have a single run with all items collated.
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.
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
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
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?
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.
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.