Dynamic Inventory — Participant Handout
Ansible for Proxmox VE · Module 06
Why static inventories go stale
A hand-maintained list of guests is correct on the day you write it. After that, every VM created in the GUI, every one deleted, every rename and every migration is a small divergence between your file and reality. You notice at the worst possible time, when a playbook fails against a host that no longer exists.
The cluster already knows all of it. An inventory plugin asks the API at run time instead of reading a file.
Read the general concept first, it applies to every cloud and platform plugin: Working with dynamic inventory.
Configuring the plugin
The plugin is community.proxmox.proxmox, from the collection you installed in module 03. Its complete option list is in the plugin documentation.
inventory/lab.proxmox.yml
An inventory source for this plugin must end in .proxmox.yml or .proxmox.yaml. With any other name the plugin declines the file silently and you get an empty inventory with no error. ansible-inventory -vvv shows the reason.
PVEAuditor
In this lab, we reuse the automation@pve token created in module 05 (PVEVMAdmin). In production, never grant administrative roles to an inventory plugin. A dedicated, read-only service account with the PVEAuditor role on / provides all the visibility the dynamic inventory needs without exposing cluster management privileges.
Using it
@all:
|--@proxmox_all_qemu:
| |--web01
|--@proxmox_all_running:
| |--web01
|--@proxmox_all_stopped:
|--@proxmox_nodes:
| |--pve01
| |--pve02
| |--pve03
|--@proxmox_pve02_qemu:
| |--web01
The generated groups follow a fixed scheme (the prefix is configurable with group_prefix):
| Group | Contains |
|---|---|
proxmox_nodes |
the cluster nodes themselves |
proxmox_all_qemu / proxmox_all_lxc |
all VMs / all containers |
proxmox_all_running / proxmox_all_stopped |
by current status |
proxmox_all_templates |
guests marked as templates |
proxmox_<node>_qemu / proxmox_<node>_lxc |
guests per node |
proxmox_pool_<pool> |
guests in a resource pool |
Nothing in that list is maintained by you. Create a guest in the GUI, run ansible-inventory --graph again, and it is there.
What the plugin actually calls
TOKEN='PVEAPIToken=automation@pve!ansible=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
PVE=https://192.168.0.1:8006/api2/json
# everything the cluster knows about, in one call - this is the inventory
curl -sk -H "Authorization: $TOKEN" "$PVE/cluster/resources" \
| jq '.data[] | select(.type=="qemu") | {vmid, name, node, status, tags}'
# the nodes
curl -sk -H "Authorization: $TOKEN" "$PVE/nodes" | jq '.data[] | {node, status}'
# the configuration of one guest - this is where want_facts gets its data
curl -sk -H "Authorization: $TOKEN" "$PVE/nodes/pve02/qemu/9001/config" | jqAPI reference: /cluster/resources.
Running that first command is the fastest way to understand what the plugin can and cannot know: if a field is not in the response, no inventory option will conjure it up. It is also a useful reality check when a group comes out empty: compare what the API returns with what you filtered on.
Facts
With want_facts: true each guest carries its Proxmox VE configuration as host variables:
{
"proxmox_vmid": 9001,
"proxmox_node": "pve02",
"proxmox_status": "stopped",
"proxmox_maxmem": 536870912,
"proxmox_tags_parsed": ["web", "staging"]
}These are available in playbooks like any other variable, and also to the grouping expressions below.
Combining static and dynamic
The cluster nodes have to exist before anything can be dynamic, so they stay in the static inventory. The guests come from the API.
ansible-playbook site.yml -i inventory/hosts.yml -i inventory/lab.proxmox.ymlansible.cfg
[defaults]
inventory = inventory/hosts.yml,inventory/lab.proxmox.ymlBoth sources are merged into one inventory. Groups from both are available in the same run, and host variables from the later source win.
Caching
Every run queries the API. On a large cluster, or in a pipeline that runs many playbooks, enable the inventory cache:
cache: true
cache_plugin: ansible.builtin.jsonfile
cache_connection: /tmp/ansible_inventory_cache
cache_timeout: 300The settings come from Ansible’s cache plugins. Be aware of the trade-off: a cached inventory is a static inventory for the length of the timeout, with all the staleness that implies.
Further reading
- Inventory plugin
community.proxmox.proxmox(every option, with examples) - Working with dynamic inventory
- How to build your inventory
ansible-inventorycommand- Proxmox VE Administration Guide: guest tags are described in the Qemu/KVM Virtual Machines chapter
- Proxmox VE API viewer: look at
/cluster/resources, which is what the plugin calls