In clouds, hosts come and go; static files are always out of date.
An inventory plugin generates hosts and groups at run time. You configure it with a YAML file whose name ends as the plugin expects (for example *.aws_ec2.yml) and whose plugin: key names it:
amazon.aws.aws_ec2,azure.azcollection.azure_rm,google.cloud.gcp_compute,kubernetes.core.k8s,community.vmware.vmware_vm_inventory,netbox.netbox.nb_inventory.
Common options:
filters: which instances to include (running, taggedenv: prod).keyed_groups: create groups from attributes, e.g. a group pertags.role, so plays can targetrole_web.groups: groups from Jinja2 conditions.compose: set host variables from attributes (ansible_host: private_ip_address).hostnames: what to call each host.cache: true: avoid querying the API on every run.
The constructed plugin applies the same keyed_groups/groups/compose logic on top of any other inventory sources, and you can point -i at a directory that mixes static files and plugins; they're merged in alphabetical order.
Enable plugins with enable_plugins in [inventory] if you restrict them, and test with ansible-inventory -i inventory/ --graph.
Legacy executable inventory scripts that print JSON still work, but plugins are the supported mechanism.
Example
# inventory/prod.aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions: [eu-west-1]
filters:
instance-state-name: running
"tag:env": prod
hostnames: [tag:Name]
keyed_groups:
- key: tags.role
prefix: role
compose:
ansible_host: private_ip_address
cache: true
cache_plugin: ansible.builtin.jsonfile
cache_connection: .inventory_cache
# ansible-inventory -i inventory/ --graph
# @all:
# |--@aws_ec2:
# |--@role_web:
# | |--web-prod-1Remember
- Plugins query APIs at run time: no stale host lists
- keyed_groups, groups and compose shape groups and variables
- constructed adds the same logic to any source; cache to save API calls
Watch out for
- Naming the config file without the plugin's required suffix, so Ansible doesn't recognise it.