Writing a Custom Ansible Dynamic Inventory Script2016-12-04
I’m writing code for a little Raspberry Pi HUD I’m running in my house, project ‘Homehud’. Naturally I manage the Raspbian system I’ve installed on it with Ansible.
One problem is that the Raspberry Pi uses a dynamic local IP, as I haven’t been able to make it use a static IP with my router. Since Ansible needs to know the IP to connect to it, this initially meant I had to manually update the inventory file with the new IP each time the Pi was rebooted, after looking it up from the connected devices list on my router’s admin page.
Of course, this can be automated.
Ansible has the ability to use a dynamic inventory rather
than a static list of addresses. If the path you’ve assigned to
ansible.cfg (or passed as
-i) is executable, it will not open the file
directly and instead it will execute it and interpret the output as JSON in a
particular format. This means you can run whatever code you like to return your
inventory, as long as you adhere to the format.
The format is documented fully in the “Developing Dynamic Inventory Sources” page in the Ansible docs, but here’s a quick sample:
At the top there’s the
all group that should contain
hosts, the connection
addresses of all hosts (normally IP addresses for SSH), plus any global
variables in the
vars object. There might also be other optional global keys.
Then there’s the
_meta key which can contain individual vars for each host
hostvars, mapped from host address to an object of variable name to
value. There may also be other keys usable under
_meta, again I’m not sure.
The rest of the top level object is a mapping from group names to lists of addresses that appear in said groups.
My script is very simple - I know the Raspberry Pi is the only device on my
local network with port 22 open, so the script simply pings port 22 of each
local address and when it finds a match, uses that as the single item appearing
in the inventory. It does this by calling
arp -a, parsing its output to find
the IP’s, and then trying to open a socket on port 22 of each. The first match
My full script follows. It might be useful as a reference for making your
own dynamic inventory scripts, considering that it’s simpler than the fully
featured cloud provider scripts included with Ansible itself. It’s written in
Python 2.7 but should be fully forwards compatible with Python 3 thanks to the
__future__ imports. Enjoy!
Working on a Django project? Check out my book Speed Up Your Django Tests which covers loads of best practices so you can write faster, more accurate tests.
One summary email a week, no spam, I pinky promise.
© 2020 All rights reserved.