Skip to main content

Inventory

Inventory Formats

Static Inventory - INI Format

# inventory/hosts
[webservers]
web1.example.com
web2.example.com
web3.example.com

[databases]
db1.example.com
db2.example.com

[loadbalancers]
lb1.example.com
lb2.example.com

[production:children]
webservers
databases
loadbalancers

[staging]
staging-web.example.com
staging-db.example.com

Static Inventory - YAML Format

# inventory/hosts.yml
all:
children:
webservers:
hosts:
web1.example.com:
web2.example.com:
web3.example.com:
databases:
hosts:
db1.example.com:
db2.example.com:
loadbalancers:
hosts:
lb1.example.com:
lb2.example.com:
production:
children:
webservers:
databases:
loadbalancers:
staging:
hosts:
staging-web.example.com:
staging-db.example.com:

Host Variables in Inventory

# inventory/hosts
[webservers]
web1.example.com http_port=80 max_connections=1000
web2.example.com http_port=8080 max_connections=2000
web3.example.com http_port=80 max_connections=1500

[databases]
db1.example.com mysql_port=3306 mysql_root_password=secret
db2.example.com mysql_port=3306 mysql_root_password=secret

[all:vars]
ansible_user=ansible
ansible_ssh_private_key_file=~/.ssh/id_rsa

Host Patterns

Basic Patterns

# All hosts
ansible all -m ping

# Single host
ansible web1.example.com -m ping

# Multiple hosts
ansible web1.example.com,web2.example.com -m ping

# Group of hosts
ansible webservers -m ping

# Multiple groups
ansible webservers,databases -m ping

# Exclude hosts
ansible all:!databases -m ping

# Intersection of groups
ansible webservers:&production -m ping

Advanced Patterns

# Wildcards
ansible web*.example.com -m ping

# Regular expressions
ansible ~web[0-9]+\.example\.com -m ping

# Range of hosts
ansible web[1:3].example.com -m ping

# First N hosts
ansible webservers[0:2] -m ping

# Specific host from group
ansible webservers[0] -m ping

# Complex patterns
ansible 'webservers:&production:!maintenance' -m ping

Group Variables

Group Variables Directory Structure

inventory/
├── hosts
└── group_vars/
├── all.yml
├── webservers.yml
├── databases.yml
├── production.yml
└── staging/
├── vars.yml
└── vault.yml

Group Variables Files

# group_vars/all.yml
---
ntp_server: pool.ntp.org
timezone: UTC
ssh_port: 22
admin_user: admin

# group_vars/webservers.yml
---
http_port: 80
max_connections: 1000
web_user: www-data
document_root: /var/www/html

# group_vars/databases.yml
---
mysql_port: 3306
mysql_user: mysql
mysql_data_dir: /var/lib/mysql
backup_hour: 2

Environment-Specific Variables

# group_vars/production.yml
---
environment: production
log_level: warn
backup_enabled: true
monitoring_enabled: true
ssl_enabled: true

# group_vars/staging.yml
---
environment: staging
log_level: debug
backup_enabled: false
monitoring_enabled: false
ssl_enabled: false

Host Variables

Host Variables Directory Structure

inventory/
├── hosts
└── host_vars/
├── web1.example.com.yml
├── web2.example.com.yml
└── db1.example.com.yml

Host Variables Files

# host_vars/web1.example.com.yml
---
server_id: web01
cpu_cores: 4
memory_gb: 8
disk_size: 100
backup_schedule: '0 1 * * *'

# host_vars/db1.example.com.yml
---
server_id: db01
cpu_cores: 8
memory_gb: 32
disk_size: 500
mysql_buffer_pool_size: 24G
mysql_max_connections: 500

Dynamic Inventory

Dynamic Inventory Script

#!/usr/bin/env python3
# inventory/dynamic_inventory.py

import json
import argparse

def get_inventory():
return {
'webservers': {
'hosts': ['web1.example.com', 'web2.example.com'],
'vars': {
'http_port': 80,
'max_connections': 1000
}
},
'databases': {
'hosts': ['db1.example.com', 'db2.example.com'],
'vars': {
'mysql_port': 3306
}
},
'_meta': {
'hostvars': {
'web1.example.com': {
'server_id': 'web01',
'cpu_cores': 4
},
'web2.example.com': {
'server_id': 'web02',
'cpu_cores': 2
}
}
}
}

def get_host_vars(host):
hostvars = get_inventory()['_meta']['hostvars']
return hostvars.get(host, {})

if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--list', action='store_true')
parser.add_argument('--host', action='store')
args = parser.parse_args()

if args.list:
print(json.dumps(get_inventory(), indent=2))
elif args.host:
print(json.dumps(get_host_vars(args.host), indent=2))

Cloud Provider Dynamic Inventory

AWS EC2

# Install AWS collection
ansible-galaxy collection install amazon.aws

# AWS credentials
export AWS_ACCESS_KEY_ID=your_access_key
export AWS_SECRET_ACCESS_KEY=your_secret_key
export AWS_DEFAULT_REGION=us-east-1

# Dynamic inventory plugin
# inventory/aws_ec2.yml
plugin: amazon.aws.aws_ec2
regions:
- us-east-1
- us-west-2
filters:
instance-state-name: running
keyed_groups:
- key: tags.Environment
prefix: env
- key: instance_type
prefix: instance_type
hostnames:
- private-ip-address
- dns-name

Azure

# inventory/azure_rm.yml
plugin: azure.azcollection.azure_rm
auth_source: auto
include_vm_resource_groups:
- myresourcegroup
keyed_groups:
- key: tags.Environment
prefix: env
- key: location
prefix: location

GCP

# inventory/gcp_compute.yml
plugin: google.cloud.gcp_compute
projects:
- my-project
auth_kind: serviceaccount
service_account_file: /path/to/service-account.json
keyed_groups:
- key: labels.environment
prefix: env
- key: machineType
prefix: machine_type

Inventory Variables

Variable Precedence

1. Command line values (highest)
2. Role defaults
3. Inventory file or script group vars
4. Inventory group_vars/all
5. Playbook group_vars/all
6. Inventory group_vars/*
7. Playbook group_vars/*
8. Inventory file or script host vars
9. Inventory host_vars/*
10. Playbook host_vars/*
11. Host facts
12. Play vars
13. Play vars_prompt
14. Play vars_files
15. Role vars
16. Block vars
17. Task vars
18. Include vars
19. Set_facts / registered vars
20. Role (and include_role) params
21. Include params
22. Extra vars (lowest)

Special Variables

# Ansible special variables
ansible_host: actual_hostname_or_ip
ansible_port: ssh_port_number
ansible_user: ssh_username
ansible_password: ssh_password
ansible_ssh_private_key_file: path_to_private_key
ansible_connection: connection_type
ansible_shell_type: shell_type
ansible_python_interpreter: python_path
ansible_become: true/false
ansible_become_method: sudo/su/pbrun/pfexec/runas
ansible_become_user: root
ansible_become_password: become_password

Connection Variables

# SSH connection variables
ansible_ssh_host: hostname_or_ip
ansible_ssh_port: 22
ansible_ssh_user: username
ansible_ssh_pass: password
ansible_ssh_private_key_file: ~/.ssh/id_rsa
ansible_ssh_common_args: '-o StrictHostKeyChecking=no'
ansible_ssh_extra_args: '-o UserKnownHostsFile=/dev/null'
ansible_scp_extra_args: '-l 1000'
ansible_sftp_extra_args: '-f /tmp/sftp.conf'

# WinRM connection variables
ansible_connection: winrm
ansible_winrm_server_cert_validation: ignore
ansible_winrm_transport: ntlm
ansible_winrm_port: 5986

Multiple Inventories

Directory Structure

inventories/
├── production/
│ ├── hosts
│ ├── group_vars/
│ └── host_vars/
├── staging/
│ ├── hosts
│ ├── group_vars/
│ └── host_vars/
└── development/
├── hosts
├── group_vars/
└── host_vars/

Using Multiple Inventories

# Specify inventory directory
ansible-playbook -i inventories/production playbook.yml

# Use multiple inventory files
ansible-playbook -i inventories/production/hosts -i inventories/staging/hosts playbook.yml

# Environment variable
export ANSIBLE_INVENTORY=inventories/production
ansible-playbook playbook.yml

Inventory Management

Testing Inventory

# List all hosts
ansible-inventory --list

# List specific group
ansible-inventory --list --limit webservers

# Show host variables
ansible-inventory --host web1.example.com

# Graph inventory
ansible-inventory --graph

# Output as YAML
ansible-inventory --list --yaml

Inventory Validation

# Validate inventory syntax
ansible-inventory --list > /dev/null

# Check host connectivity
ansible all -m ping -i inventory/hosts

# Validate with playbook
ansible-playbook --check --syntax-check -i inventory/hosts playbook.yml

Inventory Plugins

# ansible.cfg
[inventory]
enable_plugins = host_list, script, auto, yaml, ini, toml

# Custom inventory plugin
# inventory/custom.yml
plugin: custom_plugin
option1: value1
option2: value2

Best Practices

Organization

# Good structure
inventories/
├── production/
│ ├── hosts.yml
│ ├── group_vars/
│ │ ├── all.yml
│ │ ├── webservers.yml
│ │ └── databases.yml
│ └── host_vars/
│ ├── web1.example.com.yml
│ └── db1.example.com.yml
├── staging/
│ └── ...
└── development/
└── ...

Security

# Use vault for sensitive data
# group_vars/all.yml
---
admin_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
66386439653236336464626566653434...


# Separate vault files
# group_vars/webservers/vault.yml
---
ssl_private_key: !vault |
$ANSIBLE_VAULT;1.1;AES256
66386439653236336464626566653434...

Performance

# Use static inventory when possible
# Group hosts logically
# Use connection variables wisely
# Cache facts appropriately

# ansible.cfg
[defaults]
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts_cache
fact_caching_timeout = 3600

Documentation

# Document inventory structure
# inventory/README.md
# Inventory Structure
## Groups
- webservers: Web application servers
- databases: Database servers
- loadbalancers: Load balancer servers

## Environments
- production: Production environment
- staging: Staging environment
- development: Development environment

## Variables
- See group_vars/ for group-specific variables
- See host_vars/ for host-specific variables

Advanced Inventory Features

Constructed Inventory

# inventory/constructed.yml
plugin: constructed
strict: False
compose:
ansible_host: ansible_host | default(inventory_hostname)
ec2_state: ec2_state_name
ec2_arch: ec2_architecture
groups:
webservers: "'web' in inventory_hostname"
databases: "'db' in inventory_hostname"
production: "environment == 'prod'"
staging: "environment == 'staging'"
keyed_groups:
- key: ec2_instance_type
prefix: instance_type
- key: ec2_placement_region
prefix: region

Inventory Caching

# ansible.cfg
[inventory]
cache = True
cache_plugin = jsonfile
cache_timeout = 3600
cache_connection = /tmp/ansible_inventory_cache

Custom Inventory Scripts

#!/bin/bash
# inventory/custom_inventory.sh

if [ "$1" == "--list" ]; then
curl -s http://cmdb.example.com/api/hosts | jq '.'
elif [ "$1" == "--host" ]; then
curl -s http://cmdb.example.com/api/hosts/$2 | jq '.'
fi