# module-returned 'ansible\_facts' precedence?

**URL:** <https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704>\
**Category:** Ansible Developer\
**Created:** [July 18, 2014, 2:24pm UTC](https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704 "2014-07-18T14:24:16Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![chwolfe2](https://avatars.discourse-cdn.com/v4/letter/c/c68b51/32.png) [@chwolfe2](https://forum.ansible.com/u/chwolfe2)\
**Post date:** [July 18, 2014, 2:24pm UTC](https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704/1 "2014-07-18T14:24:16Z")

</div>

All,

Perhaps i’m being boneheaded, but I can’t seem to follow the exact order of application in updating the host facts that is performed by ansible on task completion. Particularly, I see the _setup cache_ is updated with the content of “ansible\_facts”, and in subsequent tasks I do see _new_ values, but for facts which _already existed_ in the namespace (specified by vars options) remain unchanged (as viewed by inject in subsequent tasks). My intuition is that the _setup cache_ is lower in precedence than the vars specified, and so when _inject_ is assembled for a subsequent task, it first injects the _setup cache_ copy(which is correct), then inventory vars, etc. until whatever _dict()_ is holding that initial value gets merged in, effectively overwriting the newer value. I’ve tried configuring _hash\_behaviour=merge_, but this doesn’t seem to have the desired effect; only appears to apply to inventory hashes.  
My question is this: How best might I feed back modified values of facts/vars such that they have the highest precedence, and ensure that said values are the ones accessed by all future tasks? Because the changes i want to make happen in a host-side _action\_module_ context, I have access to the _Runner_ instance. Other than the _ansible\_facts_ return mechanism, is there a way to modify the host’s vars through an instance of runner? I’m okay with a hack back through runner, as I wouldn’t expect the architecture of runner to change too fast to keep up with. I’d prefer not to patch _runner_ itself to achieve this, though that is the easier way to go (i think most of the logic is actually in _module_).

For a little bit of context: the action module I am writing is one which pre-validates variable content, specifying defaults for various task parameters, etc. One particular aspect is the ability to specify complex structure requirements for dict()/list(dict()) (e.g. NIC configurations). At issue here is the logic in said module which “fills out” missing fields with default values for each element in a list; since the var existed in the host namespace, we’re not creating a new fact, but modifying the existing one, and this modality doesn’t seem to be supported currently.

Thanks in advance,  
Chris Wolfe

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [July 18, 2014, 3:23pm UTC](https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704/2 "2014-07-18T15:23:27Z")

</div>

“How best might I feed back modified values of facts/vars such that they have the highest precedence, and ensure that said values are the ones accessed by all future tasks?”

Sounds like you need to be setting role defaults if you are seeing values in playbooks clobber facts and you do not want that behavior.

[http://docs.ansible.com/playbooks\_variables.html#variable-precedence-where-should-i-put-a-variable](http://docs.ansible.com/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable)

Some of your post i’m having some trouble understanding which is probably a sign you are using ansible in a “too complicated playbook” kind of way and may need to simplify, it’s a general trend from someone coming from some other tools, and might be trying to do something non-idiomatically.

Keeping variables in just one place, having only one source of truth, is the easiest way, and precedence never even comes up in those situations.

But yes, there’s much about your post I don’t understand. “modality”, etc.

---

<div class="post-metadata">

**Author:** ![chwolfe2](https://avatars.discourse-cdn.com/v4/letter/c/c68b51/32.png) [@chwolfe2](https://forum.ansible.com/u/chwolfe2)\
**Post date:** [July 18, 2014, 3:36pm UTC](https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704/3 "2014-07-18T15:36:24Z")

</div>

Thanks Michael.

I am, in fact, consciously violating the “ansible” way of doing things, however, the purpose justifies the deviation. The plan s to have a potentially widely distributed playbook for non-technical consumers. The key need is to build slightly smarter playbooks at the expense of a little development effort such that feedback to end users is cogent, and to provide a little extra filling in the blanks. i.e. keeping the top-level configuration simpler at the expense of doing more work in the playbooks. Rationale aside, the particular need is to explicitly update VARS\_CACHE, as opposed to the SETUP\_CACHE. The following patch to ansible/playbook/ **init**.py achieves the purpose: (using a new return variable ‘ansible\_vars’)

— ./playbook/ **init**.py 2014-05-23 15:08:11.000000000 -0400  
+++ ./playbook/ **init**.py.varsmod 2014-07-18 10:57:55.002591480 -0400  
@@ -438,9 +438,13 @@  
if type(res) == dict:  
facts = res.get(‘ansible\_facts’, {})  
self.SETUP\_CACHE[host].update(facts)

- newvars = res.get(‘ansible\_vars’, {})
- self.VARS\_CACHE[host].update(newvars)  
else:  
facts = result.get(‘ansible\_facts’, {})  
self.SETUP\_CACHE[host].update(facts)
- newvars = result.get(‘ansible\_vars’, {})
- self.VARS\_CACHE[host].update(newvars)  
if task.register:  
if ‘stdout’ in result and ‘stdout\_lines’ not in result:  
result[‘stdout\_lines’] = result[‘stdout’].splitlines()  
@@ -545,6 +549,7 @@  
for (host, result) in setup\_ok.iteritems():  
self.SETUP\_CACHE[host].update({‘module\_setup’: True})  
self.SETUP\_CACHE[host].update(result.get(‘ansible\_facts’, {}))
- self.VARS\_CACHE[host].update(result.get(‘ansible\_vars’,{}))  
return setup\_results

# \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

However, I was wondering if there was a way to achieve the same effect without resorting to patching playbook, and hence retain ‘distributability’. I’d be satisfied with any hack that allows me to disribute the required logic in-situ, so I was looking for a way to get back to the VARS\_CACHE from the runner instance, but i wasn’t able to trace one out.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [July 18, 2014, 6:46pm UTC](https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704/4 "2014-07-18T18:46:56Z")

</div>

Forking ansible seems a bit extreme here. I would urge you not to do so and try to understand how the tool and project organization works a bit more first.

Plenty of people will have more complex setups than yours, and many have very user-friendly fronted playbooks.

The delegation features in Ansible tower, and the way it allows for prompting of variables, serve this purpose for a lot of Ansible users.

I’ve mentioned role defaults previously as opposed to role vars, which already have lower priority than inventory variables. Do you understand those?

---

<div class="post-metadata">

**Author:** ![chwolfe2](https://avatars.discourse-cdn.com/v4/letter/c/c68b51/32.png) [@chwolfe2](https://forum.ansible.com/u/chwolfe2)\
**Post date:** [July 18, 2014, 7:38pm UTC](https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704/5 "2014-07-18T19:38:18Z")

</div>

I agree, modifying ansible is unreasonable, in general. And I am very familiar with the precedence relations between role/task/setup/inventory discovered vars/facts. But, that said, I still need to be able to modify facts/vars at higher precedence than user-supplied (inventory, group-vars, etc.). It is a corner-case, to be sure, but one that i would imagine others have encountered as well.

Consider the following toy example  
  
[group1]  
host1

\<group\_vars/group1\>

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [July 18, 2014, 8:10pm UTC](https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704/6 "2014-07-18T20:10:55Z")

</div>

I’m not sure you do.

When you say “modify facts”, can you give an example of what a fact is in this case?

I’m trying to see if what you are suggesting might not have to be a fact, and if there are nicer ways to do this.

I think there may be some ways to achieve things using the Jinja2 default operator in … fact

myvar: {{ factvar | default(some\_other\_var) }}

etc

---

<div class="post-metadata">

**Author:** ![chwolfe2](https://avatars.discourse-cdn.com/v4/letter/c/c68b51/32.png) [@chwolfe2](https://forum.ansible.com/u/chwolfe2)\
**Post date:** [July 18, 2014, 11:28pm UTC](https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704/7 "2014-07-18T23:28:33Z")

</div>

The above patch achieves my intended goals. But… I would much rather move the hacky part into a custom module to be distributed with the playbook in question. This is only possible if i can “hop out” of the current paradigm’s access pattern and access the playbook object directly, and manually manipulate the VARS\_CACHE. Of course, if there exists another mechanism to modify the VARS\_CACHE without as much hackery, I’m game for that, too. From what i gather, looking at the code, that’s not the case.

Let’s ignore, for the moment, why i might want to do this and whether or not it’s a reasonable thing to want to do.

My question is a technical one and fairly straightforward, though perhaps I was less direct previously:

From the context of a runner-side action\_plugin module  
Note: (i.e. \<playbook\_root\_dir\>/lib/ansible/runner/action\_plugins/mymodule.py)  
given only access to self.runner,  
Note: self is an ActionModule initialized with runner from \<\>  
is there a way to retrieve an object reference to the currently executing _playbook_ object,  
Note: OR any object which owns the playbook object  
_such that_  
I can modify the _playbook_ object’s _self.VARS\_CACHE[]_ member

For example:  
No, it’s not possible; _playbook_ exists outside the scope of _runner_  
Yes, it’s possible; _playbook_ is accessible via _self.runner.x.y.z.potato.playbook_  
or maybe something in the global scope _ansible\_or\_something.x.y.z.runner_

The phrasing of my original question was, in hindsight, less specific than it needed to be. I was really just looking looking for a short answer. Because i don’t have the UML, and only minimal appreciation of the architecture of ansible core, I’m not sure whether playbook owns runner or vice versa, or if they even exist in the same process space, etc. If there’s a UML diagram floating around, then a glance would answer my question. In lieu of a direct answer, I’ll search the code. If the answer is no, that’s fine, I just figured the gurus here would be able to answer quickly whether it’s feasible.

Regards,  
Chris

---

<div class="post-metadata">

**Author:** ![chwolfe2](https://avatars.discourse-cdn.com/v4/letter/c/c68b51/32.png) [@chwolfe2](https://forum.ansible.com/u/chwolfe2)\
**Post date:** [July 19, 2014, 3:13am UTC](https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704/8 "2014-07-19T03:13:51Z")

</div>

Solution (more or less):

From the action module, I can modify self.runner.vars\_cache When the runner is constructed in \_run\_task\_internal(…), the vars\_cache is set to self.VARS\_CACHE (the latter self being the playbook object); the same runner is then supplied to the action\_module’s constructor, which modules then have access to.

This persists the changes for the current play. For me, this is good enough, and I would imagine the limited lifetime of the vars\_cache is intentional ( or i could at least think of a bunch of justifications to keep it that way ).

In any event, I’m satisfied with my current hack, which doesn’t require forking runner. Thanks for the the help.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [July 19, 2014, 12:03pm UTC](https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704/9 "2014-07-19T12:03:11Z")

</div>

"Let’s ignore, for the moment, why i might want to do this and whether or not it’s a reasonable thing to want to do. "

If you’re not going to be discussing the use case and how to solve your problem in other ways, it’s going to be hard to have a discussion about how to do it better.

You’re still modifying code, which effectively means your Ansible is producing all sorts of side effects, so I’d at least ask that you not ask any ansible questions that can’t be reproduced on stock code.

We would be happy to discuss ways to manage your variable use cases, including role defaults.

---

<div class="post-metadata">

**Author:** ![chwolfe2](https://avatars.discourse-cdn.com/v4/letter/c/c68b51/32.png) [@chwolfe2](https://forum.ansible.com/u/chwolfe2)\
**Post date:** [July 19, 2014, 5:50pm UTC](https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704/10 "2014-07-19T17:50:39Z")

</div>

I don’t object to finding other solutions, but felt i was stumbling trying to get the point across. The use case is being able to make task-by-contract guarantees:  
A) the environment of the task is configured correctly and the task will _always_ succeed,  
B) the environment is misconfigured and the task fails before doing anything,  
C) the environment is mostly configured, but the task knows how to fill in the blanks)  
Each of these being checked/applied a priori with respect to task execution proper. _always_, in this context meaning if the task does fail, it won’t have been because of configuration. Particularly, some of the tasks require complex data structures, and those data structures need to be recursively validated with the same 3 goals.

At issue is goal C. For the case of scalars, the existing precedence rules function sufficiently; either the parameter has a user-supplied value, or it takes on any role-default if specified.  
However, for complex data types, this is not the case.

If X is a dict(), having fields {x=a,y=b,z=None}, specified by user  
and  
If Y is a template for our expectation of X, having fields x=a’,y=b’,z=c’,  
then  
We would like the effective value of X, as seen by the play and its tasks, to be X’ {a=X.a, b=X.b, c=Y.c’}  
thereby specifying piece-wise defaults for complex data X.

My method of achieving this is a custom module ‘requirements’ which provides all 3 guarantees. It particularly addresses the corner case of C for complex data by modifying the _self.runner.vars\_cache[host][‘X’]_ (in keeping with our example). The alternative, to return {ansible\_facts:{X:{x:X.a,y:X.b,z:Y.c’}}}, would only update the setup cache, and subsequent tasks would not see the returned value because the user-supplied value in the vars\_cache would take precedence when combining to create the environment for subsequent tasks. Therefore, X would have the original value, and X.z would still be None when accessed.

Regarding side-effects. This largely depends on the life time of the vars\_cache. For my particular purpose, the ideal lifetime for these modifications to the environment is until end of play, including any included tasks. If the vars\_cache outlives the play, then there could be unintended consequences, but, so far, that doesn’t appear to be the case. My rationale here is that any play invoking the ‘requirements’ module is imposing constraints for that play, and not the playbook as a whole. Were the piece-wise-defaults to live beyond the play, there might be issues, though the key to defending against that scenario is in rational variable naming (i.e. prefixes, etc.), which i do.

It is certainly possible to reconstruct the tasks to not require complex data, but generally impractical to do so, when tasks may require lists of dozens to hundreds of items (think manually unrolling a loop of 0-100 X\_0\_a X\_0\_b, X\_0\_c X\_1\_a, X\_1\_b … X\_99\_a … ). The alternative, in placing testing and defaulting logic throughout all of the various consumers of that data is inherently a bad idea; it detracts from the cohesiveness of the design. For the occasional parameter, it’s not a big deal, but structures that are used heavily in this mode will make the playbooks inherently un-maintainable, and tied in time to their origin.

As towards simplicity and doing too much. This feature actually allows for greater design simplicity for tasks, templates, etc. without having to re-verify or re-default a variable at each invocation, the logic becomes cleaner and visually comprehensible. Not only that, but communicates expectations in cogent and sensible way. By counterexample, having a key task fail during a rolling upgrade of 1000 machines because X.z was undefined when accessed in a template is not the optimum way to communicate mis-configuration to the end user, especially when it was known before machine 0 was touched that there would be a problem. More importantly, though, we may have something sensible to do to touch up X.z before execution (rule C). The important point is that, in order to hit all three bases, we need the ability to incrementally modify X such that X is neither the user-suplied value nor the default-value, but combination of the two. Insisting that X.z is defined up-front is unnecessarily harsh when a sensible default exists, Insisting that X is either entirely user-supplied or entirely default-supplied is unnecessarily inflexible. The middle ground lies squarely in the corner case of C.

I could also imagine a number of other scenarios where a task may want to override the user(inventory, etc.)-supplied values. Here is one:  
In a large organization, with administrative and non-administrative users use ansible playbooks to accomplish certain tasks. The playbooks, designed by the administrator, includes some auditing tasks in certain plays. These tasks, for whatever reason, depend on parameters that the administrator does not want to allow the user to modify (credentials, logtime, etc.). Said user modifies the them anyway, inducing error into the audit trails. Admittedly, this example is contrived, and there are better ways to avoid such issues, but it nonetheless illustrates a viable scenario in which it may be desirable to have the ability to mandate the content of the effective environment for subsequent tasks.(i.e. don’t allow user J to modify “audit\_username”)

So the question is not whether a particular case can be shoehorned into an ansible-idiomatic way of doing things, because that is almost always the case, modulo some hoop-jumping. The question is “how can we expand the ansible-idiomatic” way of doing things to reduce the hoop jumping. If the answer is six lines of code, then I find it hard to argue against the position (of course, there may be side effects and other concerns, but someone familiar with the code base could illuminate those).

In any event, sorry for the wall of text, and I really do appreciate your help.

Regards,  
Chris

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [July 19, 2014, 11:36pm UTC](https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704/11 "2014-07-19T23:36:23Z")

</div>

I have a bit of a problem with parsing text ambiguity, I’m a bit of a text learner.

So let me say this, and I’ll try not to be offensive, though it may sounds as such.

I see you have a [vt.edu](http://vt.edu) address. Great school.

We’ve got users on this list from Fortune 500 companies all over the place. They aren’t making their infrastructure that complicated. Many of them are making it self service.

I really feel you are overthinking this.

When I mean use case, I mean, things like “tell me what apps you are configuring and what some of the user inputs might be”.

And we can make suggestions from there.

But let’s step back and not talk code or theory for a moment, and pretend I’m a useless software executive. (Oh, wait…)

But yeah, it can’t be as hard as you are making it.

“Task by task contract guarantees” seems very abstract, almost like some PhD got struck my lightening and then had 10 cups of coffee.

There are several parts in the above though where I just couldn’t parse what you’re talking about, though, so I’m sorry this may just be super difficult to get on the same wavelength. This is one of the hardest posts for me to read all year.

---

<div class="post-metadata">

**Author:** ![Michael\_DeHaan1](https://avatars.discourse-cdn.com/v4/letter/m/5e9695/32.png) [@Michael\_DeHaan1](https://forum.ansible.com/u/Michael_DeHaan1)\
**Post date:** [July 19, 2014, 11:37pm UTC](https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704/12 "2014-07-19T23:37:43Z")

</div>

> I have a bit of a problem with parsing text ambiguity, I'm a bit of a text  
> learner.

typo: this should have been /visual/.

---

<div class="post-metadata">

**Author:** ![chwolfe2](https://avatars.discourse-cdn.com/v4/letter/c/c68b51/32.png) [@chwolfe2](https://forum.ansible.com/u/chwolfe2)\
**Post date:** [July 20, 2014, 12:35am UTC](https://forum.ansible.com/t/module-returned-ansible-facts-precedence/15704/13 "2014-07-20T00:35:46Z")

</div>

Arguably a few too many cups of coffee. 🙂
