I want to get tailor-made ansible facts from some of my hosts and figured that i could use ansible.builtin.setup with gather_subset but the results are not as I thought.
Consider the following test playbook which should produce nearly nothing:
If !all is specified then only the min subset is collected. To avoid collecting even the min subset, specify !all,!min.
BTW, I used your code with become: true, so the blanket statement is not right. Evidently the cached facts youâre seeing are only readable by root. (?) Maybe thatâs why you donât see them w/o become: true.
Okay, letâs assume gather_subset is broken with respect to ansible_date_time in such a way that it gets set/updated when it shouldnât be, and letâs also ignore whether thatâs actually the case. (I still think itâs a fact caching issue, but, whatever.)
Instead, letâs shift focus to what you want to accomplish, and how we can achieve that that in the face of strange ansible_date_time behavior.
You have fact caching enabled, so itâs normal for facts gathered in previous runs to persist even if you donât freshly gather those specific facts.
The play keyword gather_facts: true adds another execution of the setup module that occurs before the rest of the play, and the arguments for your explicit call to the module are not relevant to how that execution behaves. You can use module_defaults to affect its execution, but because you have caching youâll still have the issue where any other play that runs against this host can result in facts other than the ones you explicitly request in this play being available.
Since you are using fact caching, you will want to be aware that âgatheredâ facts are not necessarily updated when the fact is already cached. There is a configurable fact expiry period, but if you want to make absolutely sure that a fact isnât stale, you can use meta: clear_facts as a task to clean the cache (per host, not the entire cache). Because of this, ansible_date_time is not a particularly reliable fact whenever caching is enabled.
What you may want to do instead, if you need the current date_time, is to use the {{ now() }}function, which can be formatted with args.
Otherwise, youâre fighting with your fact caching which is using the default timeout of 86400 seconds, or 24 hours.
This is not correct (at least for the builtin plugins, and while it would theoretically be possible for other plugins to ignore updates it would break the API expectations and usually be a bad idea.)
The cache affects whether facts that you have not gathered in the current run are available, and (in some configurations) whether play-level gathering happens. Gathered facts are always updated.
- hosts: localhost
gather_facts: false
tasks:
- name: Uses the cached value because facts were not gathered
debug:
msg: "{{ ansible_facts.date_time.time }}"
- gather_facts:
- name: Has the freshly gathered value
debug:
msg: "{{ ansible_facts.date_time.time }}"
- gather_facts:
gather_subset: "!all,!date_time"
- name: Still the fresher value
debug:
msg: "{{ ansible_facts.date_time.time }}"
- gather_facts:
gather_subset: date_time
- name: Refreshed again
debug:
msg: "{{ ansible_facts.date_time.time }}"
PLAY [localhost] ***************************************************************
TASK [Uses the cached value because facts were not gathered] *******************
ok: [localhost] =>
msg: '14:51:14'
TASK [gather_facts] ************************************************************
ok: [localhost]
TASK [Has the freshly gathered value] ******************************************
ok: [localhost] =>
msg: '14:53:41'
TASK [gather_facts] ************************************************************
ok: [localhost]
TASK [Still the fresher value] *************************************************
ok: [localhost] =>
msg: '14:53:41'
TASK [gather_facts] ************************************************************
ok: [localhost]
TASK [Refreshed again] *********************************************************
ok: [localhost] =>
msg: '14:53:43'
I stand corrected. I thought the point of cached facts wasnât just to have it available for subsequent runs with gather_facts: false, but to improve the performance of gather_facts itself by skipping cached facts that are not expired.
Well, thatâs where we get into the question of configurations and what is meant by gather_facts. DEFAULT_GATHERING has three possible values.
- name: Play with gather_facts=true
hosts: localhost
gather_facts: true
tasks:
- debug:
msg: DEFAULT_GATHERING={{ lookup('config', 'DEFAULT_GATHERING') }}
- name: Play without gather_facts
hosts: localhost
With this playbook the default setting (implicit) gathers facts twice:
PLAY [Play with gather_facts=true] *********************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] =>
msg: DEFAULT_GATHERING=implicit
PLAY [Play without gather_facts] ***********************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
explicit only gathers facts once:
PLAY [Play with gather_facts=true] *********************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] =>
msg: DEFAULT_GATHERING=explicit
PLAY [Play without gather_facts] ***********************************************
and smart gathers facts zero times because of the cache:
PLAY [Play with gather_facts=true] *********************************************
TASK [debug] *******************************************************************
ok: [localhost] =>
msg: DEFAULT_GATHERING=smart
PLAY [Play without gather_facts] ***********************************************
However, this configuration (and the cache state) only matters for the play-level setting. The gather_facts task does not have the same logic, itâs just another task.