# Accessing Previously Set Facts in a Module

**URL:** <https://forum.ansible.com/t/accessing-previously-set-facts-in-a-module/17934>\
**Category:** Ansible Developer\
**Created:** [April 8, 2015, 10:52pm UTC](https://forum.ansible.com/t/accessing-previously-set-facts-in-a-module/17934 "2015-04-08T22:52:28Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![Julian\_Berman](https://avatars.discourse-cdn.com/v4/letter/j/a8b319/32.png) [@Julian\_Berman](https://forum.ansible.com/u/Julian_Berman)\
**Post date:** [April 8, 2015, 10:52pm UTC](https://forum.ansible.com/t/accessing-previously-set-facts-in-a-module/17934/1 "2015-04-08T22:52:28Z")

</div>

I apologize for asking this because I see a number of previous threads, but none of them hit exactly this point, or the answers don’t appear to have worked for me yet so I’m trying to figure out if I’m just completely missing something.

I have state that I need to persist between invocations of my module.

I’m following [http://docs.ansible.com/developing\_modules.html#module-provided-facts](http://docs.ansible.com/developing_modules.html#module-provided-facts), but it appears to be pretty scarce (I know documentation is hard, so I’d love to contribute back the answer to the question I’m about to ask, since it’d probably fit there quite reasonably).

I have a list of strs which my module should read, possibly modify, and then store back.

The pattern for this, from various sequences of grepping around the example modules (which don’t seem to do this), reading the PlayBook and Runner source, and just jumping back and forth, seems like it should be something like:

…  
facts = ansible\_facts(module)  
existing\_services = facts.get(“services”, {})  
new\_services = do\_stuff\_with(services)  
module.exit\_json(…, ansible\_facts={“services” : new\_services}

But after the module runs once, nothing new appears in the facts (specifically, there’s no new “services” key, and no other new keys, and even `assert "somethingIknowshouldbethere" in str(facts)` fails so it doesn’t appear to get added to some subobject in there.).

Where should my keys be going?

[https://github.com/ansible/ansible/blob/devel/lib/ansible/playbook/\_\_init\_\_.py#L519](https://github.com/ansible/ansible/blob/devel/lib/ansible/playbook/ __init__.py#L519) makes it seem like the answer is “top-level”, but yeah, I don’t see them, so I must be missing something.

If my example isn’t concrete enough and in fact it looks correct, here’s my exact module: (preface: my slightly embarrassing internal comment is now public due to me pushing that to get it working – apologies, it’s been a slightly long day of frustration): [https://github.com/Magnetic/nix-ansible/blob/3d37bceefe7b022ee0cd9ad31e6c3b773e6b4fe4/nix.py](https://github.com/Magnetic/nix-ansible/blob/3d37bceefe7b022ee0cd9ad31e6c3b773e6b4fe4/nix.py)

As a tangent, maybe this function (get\_all\_facts) isn’t supposed to be public, I don’t see any documentation for it, and specifically about what kind of object it wants as an argument, but [https://github.com/ansible/ansible/blob/devel/lib/ansible/module\_utils/facts.py#L2716-L2717](https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/facts.py#L2716-L2717) seems slightly strange, it seems to be expecting a module with a “filter” param specifically. Does that “# ======” section break mean “from here on down is private” or something, or why is it making that assumption? (I see that that code appears to be copy-pasted from the `setup` module, so maybe the answer is “it shouldn’t, and it was just copied over from there, which does have a filter parameter?”)

Appreciated,

-Julian

---

<div class="post-metadata">

**Author:** ![Jason\_DeTiberus](https://avatars.discourse-cdn.com/v4/letter/j/43a26b/32.png) [@Jason\_DeTiberus](https://forum.ansible.com/u/Jason_DeTiberus)\
**Post date:** [April 9, 2015, 2:25am UTC](https://forum.ansible.com/t/accessing-previously-set-facts-in-a-module/17934/2 "2015-04-09T02:25:15Z")

</div>

> I apologize for asking this because I see a number of previous threads, but  
> none of them hit exactly this point, or the answers don't appear to have  
> worked for me yet so I'm trying to figure out if I'm just completely  
> missing something.
> 
> I have state that I need to persist between invocations of my module.
> 
> I'm  
> following [http://docs.ansible.com/developing\_modules.html#module-provided-facts](http://docs.ansible.com/developing_modules.html#module-provided-facts),  
> but it appears to be pretty scarce (I know documentation is hard, so I'd  
> love to contribute back the answer to the question I'm about to ask, since  
> it'd probably fit there quite reasonably).
> 
> I have a list of strs which my module should read, possibly modify, and  
> then store back.
> 
> The pattern for this, from various sequences of grepping around the example  
> modules (which don't seem to do this), reading the PlayBook and Runner  
> source, and just jumping back and forth, seems like it should be something  
> like:
> 
> &nbsp;&nbsp;&nbsp;...  
> &nbsp;&nbsp;&nbsp;facts = ansible\_facts(module)

^ This will retrieve the base ansible facts, so unless you need to consume them, you wouldn't want to do this (also, you'd need `from ansible.module_utils.facts import *` for this to work as well)

> &nbsp;&nbsp;&nbsp;existing\_services = facts.get("services", {})

^ This just returns an empty hash since services does not exist in the dict returned fro ansible\_facts above.

> &nbsp;&nbsp;&nbsp;new\_services = do\_stuff\_with(services)  
> &nbsp;&nbsp;&nbsp;module.exit\_json(..., ansible\_facts={"services" : new\_services}

^ When specifying a dictionary this way, the quotes should be left off of services. I suspect you are losing the dictionary you are passing back because of the json conversion that exit\_json is doing. At this point, the ansible\_facts variable should be set to a python dictionary.

> But after the module runs once, nothing new appears in the facts  
> (specifically, there's no new "services" key, and no other new keys, and  
> even `assert "somethingIknowshouldbethere" in str(facts)` fails so it  
> doesn't appear to get added to some subobject in there.).

You will not see the services value from within your module, you are generating it within your module. The approach I took for returning facts and persisting data between runs was to use a combination of the module provided facts and local facts: [http://docs.ansible.com/playbooks\_variables.html#local-facts-facts-d](http://docs.ansible.com/playbooks_variables.html#local-facts-facts-d)

You can see how I'm doing it here: [https://github.com/openshift/openshift-ansible/blob/master/roles/openshift\_facts/library/openshift\_facts.py](https://github.com/openshift/openshift-ansible/blob/master/roles/openshift_facts/library/openshift_facts.py) but basically, I'm storing data that I want to persist in /etc/ansible/openshift.fact and then using that file to determine what "facts" to return based on the local facts, base defaults, and provider specified defaults.

> Where should my keys be going?
> 
> [https://github.com/ansible/ansible/blob/devel/lib/ansible/playbook/\_\_init\_\_.py#L519](https://github.com/ansible/ansible/blob/devel/lib/ansible/playbook/ __init__.py#L519)  
> makes it seem like the answer is "top-level", but yeah, I don't see them,  
> so I must be missing something.
> 
> If my example isn't concrete enough and in fact it looks correct, here's my  
> exact module: (preface: my slightly embarrassing internal comment is now  
> public due to me pushing that to get it working -- apologies, it's been a  
> slightly long day of frustration):  
> [https://github.com/Magnetic/nix-ansible/blob/3d37bceefe7b022ee0cd9ad31e6c3b773e6b4fe4/nix.py](https://github.com/Magnetic/nix-ansible/blob/3d37bceefe7b022ee0cd9ad31e6c3b773e6b4fe4/nix.py)

Changing line 71 to: 'ansible\_facts={services: nix.services},' should be all that you need. You shouldn't need to import from ansible.module\_utils.facts

Hope that helps,

Jason DeTiberus

---

<div class="post-metadata">

**Author:** ![Julian\_Berman](https://avatars.discourse-cdn.com/v4/letter/j/a8b319/32.png) [@Julian\_Berman](https://forum.ansible.com/u/Julian_Berman)\
**Post date:** [April 9, 2015, 3:33am UTC](https://forum.ansible.com/t/accessing-previously-set-facts-in-a-module/17934/3 "2015-04-09T03:33:30Z")

</div>

Hey Jason, thanks so much for the info. I’m going to have a look at your Openshift module tomorrow, so the only thing in your reply that I’m not sure I understand initially is what you mean about services and line 71 – I’m passing a Python dictionary with one key, “services”, and expecting to retrieve that later, when the module runs again a second time – if I remove the quotes, I should get a NameError, because I have no local called `services` – am I misunderstanding what you mean, or is there more special sauce somewhere that’s doing something unexpected there?

---

<div class="post-metadata">

**Author:** ![Jason\_DeTiberus](https://avatars.discourse-cdn.com/v4/letter/j/43a26b/32.png) [@Jason\_DeTiberus](https://forum.ansible.com/u/Jason_DeTiberus)\
**Post date:** [April 9, 2015, 1:54pm UTC](https://forum.ansible.com/t/accessing-previously-set-facts-in-a-module/17934/4 "2015-04-09T13:54:09Z")

</div>

The main thing is that any "facts" that you return in the ansible\_facts dictionary is only going to be available after your module is run, it won't be persisted in any way by default. Your module will have to provide a way to persist the data between runs. In my case, I used the local\_facts approach for storing the data so that it can also be retrieved through local\_facts when ansible is run against the host even if my openshift\_facts module has not been run.

Don't mind me on the syntax bit, I don't use a single language with enough regularity to keep all the syntax clear in my head, I was thinking of the way you would build a python dictionary using dict() instead of {}.

Hope that clarifies things a bit.

---

<div class="post-metadata">

**Author:** ![Julian\_Berman](https://avatars.discourse-cdn.com/v4/letter/j/a8b319/32.png) [@Julian\_Berman](https://forum.ansible.com/u/Julian_Berman)\
**Post date:** [April 9, 2015, 2:03pm UTC](https://forum.ansible.com/t/accessing-previously-set-facts-in-a-module/17934/5 "2015-04-09T14:03:13Z")

</div>

Hah understandable.

What specifically is the lifecycle of facts then if they’re not persisted? When you say “between runs” – what I’m looking for is for

`ansible-playbook foo.yaml`

where foo.yaml contains

- name: first step  
mymodule: service=foo

- name: second step  
mymodule: service=bar

and then goes off and runs some other task file as well, with service=baz,

that by the time I see service=baz, I should have a list of all three, “foo”, “bar”, and “baz” – that’s all the persistence I need, and I want it to disappear once ansible-playbook exits. Is even that not what is persisted with facts? If so what possibly can you use them for if they disappear as soon as the module exits? Might as well just use Python objects, which at least will persist until the process exits?

Thanks again,

-J

---

<div class="post-metadata">

**Author:** ![Jason\_DeTiberus](https://avatars.discourse-cdn.com/v4/letter/j/43a26b/32.png) [@Jason\_DeTiberus](https://forum.ansible.com/u/Jason_DeTiberus)\
**Post date:** [April 9, 2015, 2:48pm UTC](https://forum.ansible.com/t/accessing-previously-set-facts-in-a-module/17934/6 "2015-04-09T14:48:56Z")

</div>

Okay, so the facts will be available to the rest of the playbook (and any included roles, playbooks, tasks, etc after the module has been called). I'm not sure how you would access the runtime facts from within the module, or if it is even possible. If you try to retrieve the facts using ansible.module\_utils.facts, you will get the ansible generated facts only.

The main purpose of facts are to make decisions later within the playbook. The current modules that aggregate actions (yum, apt, etc) are currently done by workarounds in the ansible code and not natively in the module. I \*believe\* that there are plans for v2 to make this more generic, but someone from Ansible would have to confirm/deny that statement.

In my case, I need to persist the data between playbook runs, not just multiple module runs within a playbook. You might have to require a parameter to our module for the user to provide the output of hostvars[inventory\_hostname] to consume the current facts as a workaround.

---

<div class="post-metadata">

**Author:** ![Brian\_Coca](https://avatars.discourse-cdn.com/v4/letter/b/6de8d8/32.png) [@Brian\_Coca](https://forum.ansible.com/u/Brian_Coca)\
**Post date:** [April 9, 2015, 4:23pm UTC](https://forum.ansible.com/t/accessing-previously-set-facts-in-a-module/17934/7 "2015-04-09T16:23:56Z")

</div>

modules don't get data passed to them automatically, so if you add a  
fact, you need to explicitly pas it to the module

about with\_items optimization, this has been on our wishlist for a long time now

---

<div class="post-metadata">

**Author:** ![Julian\_Berman](https://avatars.discourse-cdn.com/v4/letter/j/a8b319/32.png) [@Julian\_Berman](https://forum.ansible.com/u/Julian_Berman)\
**Post date:** [April 9, 2015, 4:30pm UTC](https://forum.ansible.com/t/accessing-previously-set-facts-in-a-module/17934/8 "2015-04-09T16:30:44Z")

</div>

Ah cool, thanks for the confirmation. And I’d need to persist the fact myself right? Or how would I be able to pass it to the module, and whatever way that is, why does it need to involve ansible at all at that point? Might as well just pass Python objects around outside of ansible’s framework (and AnsibleModule)?

To me I’d have expected ansible to pass me a Python object that it passes to each module during invocation where I can hang state, and then it disappears at the end of the run. Is that the kind of thing that’s on the wishlist?

---

<div class="post-metadata">

**Author:** ![Hank\_Beatty](https://avatars.discourse-cdn.com/v4/letter/h/f6c823/32.png) [@Hank\_Beatty](https://forum.ansible.com/u/Hank_Beatty)\
**Post date:** [April 16, 2015, 7:03pm UTC](https://forum.ansible.com/t/accessing-previously-set-facts-in-a-module/17934/9 "2015-04-16T19:03:27Z")

</div>

Hello Julian,

Did you ever come up with a solution to this? I’m wanting to do the exact same thing.

Thanks,  
Hank

---

<div class="post-metadata">

**Author:** ![Julian\_Berman](https://avatars.discourse-cdn.com/v4/letter/j/a8b319/32.png) [@Julian\_Berman](https://forum.ansible.com/u/Julian_Berman)\
**Post date:** [April 17, 2015, 2:59pm UTC](https://forum.ansible.com/t/accessing-previously-set-facts-in-a-module/17934/10 "2015-04-17T14:59:33Z")

</div>

I haven’t yet, but I took a break to work on a few other things, so I’ll be coming back to it next week I hope.

Ansible doesn’t make persisting to a file trivial yet either from what I can tell, since you don’t get access to `ansible_remote_tmp` (or I haven’t found it yet), so I don’t yet see a way to be able to even store state in a file during a run in a way that gets cleaned up at the end.

But if / when I come up with a solution I’ll post it here.
