Files
infra-automation/docs/inventory.md
Infrastructure Team 04a381e0d5 Add comprehensive documentation
- 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
2025-11-10 22:52:03 +01:00

13 KiB

Ansible Inventory Configuration

This document describes the dynamic and static inventory configurations for the Ansible infrastructure.

Table of Contents

  1. Overview
  2. Inventory Structure
  3. Dynamic Inventory Solutions
  4. Static/Hybrid Inventory
  5. Usage Examples
  6. 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 hostname
  • vm_uuid: Libvirt UUID
  • vm_state: Current state (running, shutoff, etc.)
  • vm_vcpus: Number of virtual CPUs
  • vm_memory_mb: Memory allocation in MB
  • vm_networks: Network interface details
  • ansible_host: IP address (if available)
  • ansible_ssh_common_args: ProxyJump configuration
  • hypervisor: 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 hosts
  • kvm_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/config exists and is readable
  • Verify Host declarations are properly formatted
  • Run with --list to 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/ and host_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/config has 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