- Add linux-vm-deployment.md with complete deployment guide - Architecture overview and security model - Supported distributions matrix - LVM partitioning specifications - Distribution-specific configurations - Troubleshooting procedures - Performance tuning guidelines
13 KiB
Ansible Inventory Configuration
This document describes the dynamic and static inventory configurations for the Ansible infrastructure.
Table of Contents
- Overview
- Inventory Structure
- Dynamic Inventory Solutions
- Static/Hybrid Inventory
- Usage Examples
- Troubleshooting
Overview
Per the CLAUDE.md guidelines, this infrastructure uses dynamic inventories as the primary inventory source, with static inventories permitted for development environments only.
Available Inventory Solutions
| Solution | Type | Use Case | Status |
|---|---|---|---|
| SSH Config Parser | Dynamic | Quick discovery from SSH config | ✅ Active |
| Libvirt/KVM Plugin | Dynamic | Real-time VM discovery | ✅ Active |
| Static YAML | Static/Hybrid | Development environment | ✅ Active |
Inventory Structure
inventories/
├── production/ # Production environment (dynamic only)
│ ├── group_vars/
│ │ └── all.yml
│ └── [dynamic inventory configs]
├── staging/ # Staging environment (dynamic only)
│ ├── group_vars/
│ │ └── all.yml
│ └── [dynamic inventory configs]
└── development/ # Development environment
├── hosts.yml # Static/hybrid inventory
├── libvirt_kvm.yml # Libvirt dynamic config
├── group_vars/
│ ├── all.yml
│ ├── kvm_guests.yml
│ └── hypervisors.yml
└── host_vars/
Dynamic Inventory Solutions
1. SSH Config Parser (ssh_config_inventory.py)
Location: /opt/ansible/plugins/inventory/ssh_config_inventory.py
Description
Parses ~/.ssh/config to automatically generate Ansible inventory with proper grouping and connection parameters.
Features
- Automatic host discovery from SSH config
- Intelligent grouping by host characteristics
- ProxyJump support for nested VM access
- No external dependencies (pure Python)
Usage
# List all hosts and groups
python3 plugins/inventory/ssh_config_inventory.py --list
# Get variables for specific host
python3 plugins/inventory/ssh_config_inventory.py --host pihole
# Use with ansible commands
ansible all -i plugins/inventory/ssh_config_inventory.py --list-hosts
# Use with playbooks
ansible-playbook -i plugins/inventory/ssh_config_inventory.py site.yml
Host Categorization Logic
| Category | Criteria |
|---|---|
external_hosts |
Public IPs, no ProxyJump, non-ansible user |
hypervisors |
ForwardAgent enabled, specific users (grok) |
dns_servers |
ansible user + ProxyJump + hostname contains 'pihole'/'dns' |
mail_servers |
ansible user + ProxyJump + hostname contains 'mail'/'mx' |
development |
ansible user + ProxyJump + hostname contains 'dev'/'test'/'derp' |
Generated Inventory Structure
{
"all": {
"children": ["external_hosts", "hypervisors", "kvm_guests"]
},
"external_hosts": {
"hosts": ["odin"]
},
"hypervisors": {
"hosts": ["grokbox"]
},
"kvm_guests": {
"children": ["dns_servers", "mail_servers", "development", "uncategorized"],
"vars": {
"ansible_user": "ansible",
"ansible_ssh_common_args": "-o StrictHostKeyChecking=accept-new"
}
},
"_meta": {
"hostvars": { ... }
}
}
2. Libvirt/KVM Dynamic Inventory (libvirt_kvm.py)
Location: /opt/ansible/plugins/inventory/libvirt_kvm.py
Description
Queries libvirt hypervisors directly to discover KVM guest VMs in real-time, including their state, resources, and network configuration.
Features
- Real-time VM discovery via libvirt API
- VM state detection (running, stopped, paused)
- Automatic IP address detection
- Resource information (vCPUs, memory, networks)
- Multiple hypervisor support
- ProxyJump configuration
Requirements
# Debian/Ubuntu
apt-get install python3-libvirt
# RHEL/Fedora/Rocky
dnf install python3-libvirt
Configuration
Set environment variables or use configuration file:
# Environment variables
export LIBVIRT_DEFAULT_URI="qemu+ssh://grok@grok.home.serneels.xyz/system"
export LIBVIRT_HYPERVISOR_NAME="grokbox"
Or use YAML configuration file: inventories/development/libvirt_kvm.yml
Usage
# List all VMs
python3 plugins/inventory/libvirt_kvm.py --list
# Get specific VM details
python3 plugins/inventory/libvirt_kvm.py --host mymx
# Use with ansible
ansible running_vms -i plugins/inventory/libvirt_kvm.py -m ping
# Use with playbooks
ansible-playbook -i plugins/inventory/libvirt_kvm.py playbooks/update.yml
Generated Groups
| Group | Description |
|---|---|
hypervisors |
KVM hypervisor hosts |
kvm_guests |
All guest VMs |
running_vms |
VMs in running state |
stopped_vms |
VMs not running (shutoff, paused, etc.) |
Host Variables
Each VM includes:
vm_name: VM hostnamevm_uuid: Libvirt UUIDvm_state: Current state (running, shutoff, etc.)vm_vcpus: Number of virtual CPUsvm_memory_mb: Memory allocation in MBvm_networks: Network interface detailsansible_host: IP address (if available)ansible_ssh_common_args: ProxyJump configurationhypervisor: Parent hypervisor name
Example Output
{
"running_vms": {
"hosts": ["mymx", "pihole", "derp"]
},
"_meta": {
"hostvars": {
"pihole": {
"vm_name": "pihole",
"vm_uuid": "6d714c93-16fb-41c8-8ef8-9001f9066b3a",
"vm_state": "running",
"vm_vcpus": 2,
"vm_memory_mb": 2048,
"ansible_host": "192.168.122.12",
"ansible_ssh_common_args": "-o ProxyJump=grokbox -o StrictHostKeyChecking=accept-new",
"hypervisor": "grokbox"
}
}
}
}
Static/Hybrid Inventory
Location: /opt/ansible/inventories/development/hosts.yml
Description
Manually maintained static inventory for the development environment with detailed host metadata and configuration.
Structure
all:
children:
external_hosts: # Public-facing hosts
hypervisors: # KVM hypervisor hosts
kvm_guests: # Virtual machine guests
children:
dns_servers:
mail_servers:
development:
uncategorized:
Group Variables
Variables are defined in group_vars/ directory:
all.yml: Global variables for all hostskvm_guests.yml: Common VM configuration (LVM, networking, ProxyJump)hypervisors.yml: Hypervisor-specific settings (libvirt, QEMU)
Host Variables
Host-specific variables can be placed in host_vars/ directory:
host_vars/
├── pihole.yml
├── mymx.yml
└── derp.yml
Usage
# List hosts
ansible all -i inventories/development/hosts.yml --list-hosts
# Run playbook
ansible-playbook -i inventories/development/hosts.yml site.yml
# Target specific group
ansible dns_servers -i inventories/development/hosts.yml -m ping
Usage Examples
Example 1: List All Hosts (Dynamic)
# Using SSH config parser
ansible all -i plugins/inventory/ssh_config_inventory.py --list-hosts
# Using libvirt inventory
ansible all -i plugins/inventory/libvirt_kvm.py --list-hosts
Example 2: Ping All Running VMs
ansible running_vms -i plugins/inventory/libvirt_kvm.py -m ping
Example 3: Run Playbook Against KVM Guests
ansible-playbook -i inventories/development/hosts.yml \
--limit kvm_guests \
playbooks/system-update.yml
Example 4: Check Host Variables
# Using dynamic inventory
ansible-inventory -i plugins/inventory/libvirt_kvm.py --host pihole
# Using static inventory
ansible-inventory -i inventories/development/hosts.yml --host pihole --yaml
Example 5: Multiple Inventory Sources
You can combine multiple inventory sources:
ansible-playbook -i inventories/development/hosts.yml \
-i plugins/inventory/libvirt_kvm.py \
site.yml
Example 6: Filter by Group
# Target only mail servers
ansible mail_servers -i plugins/inventory/ssh_config_inventory.py -m setup
# Target only hypervisors
ansible hypervisors -i inventories/development/hosts.yml -m shell -a "virsh list --all"
Ansible Configuration
Configure default inventory in ansible.cfg:
[defaults]
inventory = ./inventories/development/hosts.yml
# Or use dynamic:
# inventory = ./plugins/inventory/libvirt_kvm.py
# Enable multiple inventory sources
# inventory = ./inventories/development/hosts.yml,./plugins/inventory/libvirt_kvm.py
# Inventory plugins path
inventory_plugins = ./plugins/inventory
# Enable fact caching for performance
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 86400
Troubleshooting
SSH Config Parser Issues
Problem: Hosts not appearing in inventory
Solution:
- Check
~/.ssh/configexists and is readable - Verify Host declarations are properly formatted
- Run with
--listto see parsed output - Check for Python syntax errors
Problem: Incorrect host categorization
Solution:
- Review categorization logic in
_categorize_host()method - Add custom categorization rules
- Use static inventory for specific grouping needs
Libvirt Inventory Issues
Problem: python3-libvirt not installed
Solution:
# Debian/Ubuntu
sudo apt-get install python3-libvirt
# RHEL/Rocky/Fedora
sudo dnf install python3-libvirt
Problem: Connection to hypervisor fails
Solution:
- Verify SSH access to hypervisor:
ssh grok@grok.home.serneels.xyz - Check libvirt URI:
virsh -c qemu+ssh://grok@grok.home.serneels.xyz/system list - Ensure SSH keys are properly configured
- Check SSH agent forwarding if needed
Problem: VMs discovered but no IP addresses
Solution:
- VMs may not have DHCP leases yet
- Check VM is fully booted:
virsh dominfo <vm_name> - Manually query:
virsh domifaddr <vm_name> - Use static inventory with known IP addresses
Static Inventory Issues
Problem: YAML syntax errors
Solution:
- Validate YAML syntax:
yamllint inventories/development/hosts.yml - Check indentation (use 2 spaces)
- Verify with:
ansible-inventory -i inventories/development/hosts.yml --list
Problem: Variables not being applied
Solution:
- Check variable precedence order
- Verify
group_vars/andhost_vars/file names match group/host names - Use
ansible-inventory --host <hostname>to debug variable merging
General Debugging
# Verify inventory parsing
ansible-inventory -i <inventory_source> --list
# Check specific host variables
ansible-inventory -i <inventory_source> --host <hostname>
# Graph inventory structure
ansible-inventory -i <inventory_source> --graph
# Test connectivity
ansible all -i <inventory_source> -m ping -vvv
# Dry run playbook
ansible-playbook -i <inventory_source> site.yml --check --diff
Security Considerations
SSH Config Parser
- ✅ No credentials stored in inventory
- ✅ Uses existing SSH configuration
- ⚠️ Ensure
~/.ssh/confighas proper permissions (600)
Libvirt Inventory
- ✅ Uses SSH key authentication
- ✅ No passwords in configuration
- ⚠️ Requires SSH access to hypervisor
- ⚠️ Libvirt connection string may be logged
Static Inventory
- ✅ Version controlled and auditable
- ⚠️ Use Ansible Vault for sensitive variables
- ⚠️ Never commit unencrypted credentials
Best Practices
- Use Ansible Vault for secrets:
ansible-vault encrypt group_vars/all/vault.yml - Rotate SSH keys regularly (90-180 days per CLAUDE.md)
- Use ProxyJump/bastion hosts for nested VM access
- Enable SSH ControlMaster for connection reuse
- Implement inventory caching for large infrastructures
Performance Optimization
Caching
Enable fact caching in ansible.cfg:
[defaults]
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 86400
Parallelism
Adjust fork count:
[defaults]
forks = 20
SSH Connection Reuse
Configure ControlMaster in ~/.ssh/config:
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600s
References
Document Version: 1.0.0 Last Updated: 2025-11-10 Maintainer: Ansible Infrastructure Team