Inventory Management
Inventory Basics
Static Inventory
# inventory/production
[webservers]
web1.example.com ansible_host=192.168.1.10
web2.example.com
[dbservers]
db[01:03].example.com
[loadbalancers]
lb01.example.com
lb02.example.com
[webservers:vars]
http_port=80
proxy_timeout=5
[all:vars]
ansible_user=deploy
ansible_ssh_private_key_file=~/.ssh/id_rsa
# inventory/production.yml
all:
children:
webservers:
hosts:
web1.example.com:
ansible_host: 192.168.1.10
web2.example.com:
vars:
http_port: 80
proxy_timeout: 5
dbservers:
hosts:
db[01:03].example.com:
loadbalancers:
hosts:
lb01.example.com:
lb02.example.com:
vars:
ansible_user: deploy
ansible_ssh_private_key_file: ~/.ssh/id_rsa
Dynamic Inventory
Dynamic Inventory (continued)
AWS Dynamic Inventory
#!/usr/bin/env python3
import boto3
import json
def get_ec2_instances():
ec2 = boto3.client('ec2')
instances = ec2.describe_instances()
inventory = {
'aws_ec2': {
'hosts': []
},
'_meta': {
'hostvars': {}
}
}
for reservation in instances['Reservations']:
for instance in reservation['Instances']:
if instance['State']['Name'] == 'running':
dns_name = instance['PublicDnsName']
inventory['aws_ec2']['hosts'].append(dns_name)
inventory['_meta']['hostvars'][dns_name] = {
'ansible_host': instance['PublicIpAddress'],
'instance_id': instance['InstanceId'],
'instance_type': instance['InstanceType']
}
return inventory
if __name__ == '__main__':
print(json.dumps(get_ec2_instances(), indent=2))
Using Dynamic Inventory
# Make script executable
chmod +x inventory/aws_dynamic.py
# Test inventory script
./inventory/aws_dynamic.py --list
# Use with ansible
ansible-playbook -i inventory/aws_dynamic.py site.yml
Inventory Patterns
Using Patterns
# All hosts
ansible all -i inventory -m ping
# Specific group
ansible webservers -i inventory -m ping
# Multiple groups
ansible webservers:dbservers -i inventory -m ping
# Excluding groups
ansible all:!webservers -i inventory -m ping
# Using wildcards
ansible "*.example.com" -i inventory -m ping
# Using regex
ansible "~web[0-9]+" -i inventory -m ping
Inventory Variables
Host and Group Variables
# host_vars/web1.example.com.yml
---
http_port: 8080
app_env: production
ssl_enabled: true
# group_vars/webservers.yml
---
nginx_version: stable
php_version: "8.1"
max_clients: 200
Directory Structure
inventory/
├── production/
│ ├── hosts
│ ├── group_vars/
│ │ ├── all.yml
│ │ ├── webservers.yml
│ │ └── dbservers.yml
│ └── host_vars/
│ ├── web1.example.com.yml
│ └── db1.example.com.yml
└── staging/
├── hosts
├── group_vars/
└── host_vars/
Connection Methods
SSH Configuration
[webservers]
web1.example.com ansible_connection=ssh ansible_user=deploy
web2.example.com ansible_port=2222 ansible_ssh_private_key_file=~/.ssh/web2.pem
[windows]
win1.example.com ansible_connection=winrm ansible_winrm_transport=basic
Connection Variables
# Group level connection settings
[production:vars]
ansible_connection=ssh
ansible_user=deploy
ansible_port=22
ansible_ssh_private_key_file=~/.ssh/id_rsa
ansible_ssh_common_args='-o StrictHostKeyChecking=no'
Inventory Plugins
Using Built-in Plugins
# aws_ec2.yml
plugin: aws_ec2
regions:
- us-east-1
- us-west-2
keyed_groups:
- prefix: tag
key: tags
- prefix: instance_type
key: instance_type
filters:
instance-state-name: running
Custom Inventory Plugin
from ansible.plugins.inventory import BaseInventoryPlugin
class InventoryModule(BaseInventoryPlugin):
NAME = 'custom_inventory'
def verify_file(self, path):
return True
def parse(self, inventory, loader, path, cache):
super(InventoryModule, self).parse(inventory, loader, path, cache)
self.inventory.add_host('custom_host')
self.inventory.set_variable('custom_host', 'custom_var', 'value')
Inventory Validation
Testing Inventory
# List all hosts
ansible-inventory -i inventory --list
# List host variables
ansible-inventory -i inventory --host web1.example.com
# Graph inventory
ansible-inventory -i inventory --graph
# YAML output
ansible-inventory -i inventory --list -y
Inventory Verification
- name: Verify inventory connectivity
hosts: all
gather_facts: no
tasks:
- name: Ping all hosts
ping:
register: ping_result
- name: Display unreachable hosts
debug:
msg: "Host {{ inventory_hostname }} is unreachable"
when: ping_result.unreachable is defined
Best Practices
Organization
inventory/
├── production/
│ ├── hosts # Production inventory file
│ ├── group_vars/ # Production group variables
│ └── host_vars/ # Production host variables
├── staging/
│ ├── hosts # Staging inventory file
│ ├── group_vars/ # Staging group variables
│ └── host_vars/ # Staging host variables
└── testing/
├── hosts # Testing inventory file
├── group_vars/ # Testing group variables
└── host_vars/ # Testing host variables
Security
# Vault-encrypted group variables
---
db_credentials:
user: !vault |
$ANSIBLE_VAULT;1.1;AES256
...
password: !vault |
$ANSIBLE_VAULT;1.1;AES256
...
Documentation
# inventory/production/hosts
# Production Environment Inventory
# Last Updated: 2024-03-15
# Contact: [email protected]
[webservers]
# Frontend web servers
web1.example.com # Primary web server
web2.example.com # Secondary web server
[dbservers]
# Database servers
db1.example.com # Primary database
db2.example.com # Replica database
Troubleshooting
Common Issues
# Test SSH connection
ssh -v [email protected]
# Check inventory membership
ansible-inventory -i inventory --graph
# Verify variables
ansible -i inventory web1.example.com -m debug -a "var=hostvars[inventory_hostname]"
# Test connection with verbose output
ansible -i inventory web1.example.com -m ping -vvv
Debug Configuration
[defaults]
inventory_plugins = ~/.ansible/plugins/inventory:/usr/share/ansible/plugins/inventory
host_key_checking = False
timeout = 30
[inventory]
enable_plugins = host_list, script, auto, yaml, ini, toml
Maintenance
Version Control
# .gitignore
*.retry
.vault_pass
inventory/**/vault.yml
Inventory Updates
# Export current inventory
ansible-inventory -i inventory --list --yaml > inventory_snapshot.yml
# Compare inventories
diff inventory_snapshot.yml new_inventory.yml
# Validate new inventory
ansible-inventory -i new_inventory.yml --graph