Here I am again with Ansible’s local facts, but this time on Windows nodes, where the local facts behave differently.
Local fact files on Unix/Linux must be named *.fact
irrespective of whether they contain INI or JSON or whether they are executable programs which emit JSON, and they are searched for in a default fact_path
which is typically /etc/ansible/facts.d
(or /usr/local/etc/ansible/facts.d
on BSD systems).
There’s no default fact directory for Windows nodes, but we specify one with the fact_path
parameter to the setup
module or in an ansible.cfg
file:
[defaults]
nocows = 1
fact_path = c:/users/r1/facts
That directory must exist and it MUST contain PowerShell (*.ps1
) or JSON (*.json
) files. The PowerShell scripts output objects which Ansible formats as JSON:
@{
username = 'janej'
lat = 48.856826
lon = 2.292713
}
When Ansible’s setup
module runs, we obtain the following fact from the Windows node:
"ansible_os_family": "Windows",
"ansible_osm": {
"lat": 48.856826,
"lon": 2.292713,
"username": "janej"
}
Note that Ansible places these objects alongside other Ansible facts, whereas on Unix, if I have a JSON file /etc/ansible/facts.d/osm.fact
, Ansible returns osm
nested under ansible_local
:
"ansible_os_family": "Darwin",
"ansible_local": {
"osm": {
"lat": 48.856826,
"lon": 2.292713,
"username": "janej"
}
}
dynamic
On Unix/Linux *.fact
files may be executable and return JSON, so I install my program as /etc/ansible/facts.d/hungry.fact
$ /etc/ansible/facts.d/hungry.fact
{"id":4,"meal":"dinner","dish":"tikka masala"}
The utility is executed during setup
and the result is:
"ansible_local": {
"hungry": {
"dish": "tikka masala",
"id": 4,
"meal": "dinner"
},
"osm": {
"lat": 48.856826,
"lon": 2.292713,
"username": "janej"
}
}
On Windows nodes fact files MUST be *.ps1
so I figure out^W^W google how to invoke a program from a PowerShell script and produce this masterpiece in a file called currybeer.ps1
:
Invoke-Expression "& `"C:\Users\r1\facts\hungry.exe`" /run /exit /SilentMode"
Sadly, that doesn’t do what I thought it would: the PowerShell script is returning a string:
"ansible_currybeer": "{\"id\":4,\"meal\":\"dinner\",\"dish\":\"tikka masala\"}"
A bit more figuring out later, I add | ConvertFrom-Json
to the .ps1 script, and Ansible correctly interprets its output:
"ansible_currybeer": {
"dish": "tikka masala",
"id": 4,
"meal": "dinner"
},
"ansible_osm": {
"lat": 48.856826,
"lon": 2.292713,
"username": "janej"
},
I can now use these facts like any others:
- hosts: win
gather_facts: true
tasks:
- debug: msg="{{ ansible_currybeer.dish }} for {{ ansible_currybeer.meal }}"
and look forward to this evening:
TASK [debug] *************************
ok: [192.168.1.163] => {
"msg": "tikka masala for dinner"
}
I don’t know why Ansible nests local facts differently on Windows nodes, and I don’t see an advantage in doing so.
And if you need inspiration, we’re collecting ideas for using local facts