Remove static inventory, use only dynamic libvirt inventory

Remove static hosts.yml inventory file and configure pure dynamic
inventory discovery using community.libvirt.libvirt plugin.

Changes:

1. Removed Static Inventory:
   - Deleted inventories/development/hosts.yml
   - All host definitions now come from libvirt dynamic discovery
   - Complies with CLAUDE.md requirement for dynamic inventories

2. Updated libvirt_kvm.yml Dynamic Inventory:
   - Changed URI from local to remote: qemu+ssh://grok@grok.home.serneels.xyz/system
   - Configures automatic VM discovery from grokbox hypervisor
   - Creates dynamic groups: kvm_guests, running_vms, small_vms, large_vms
   - Creates keyed groups by state and OS
   - Extracts IP addresses from guest_info

3. Created Host Variables Override:
   - inventories/development/host_vars/pihole.yml
   - inventories/development/host_vars/mymx.yml
   - inventories/development/host_vars/derp.yml
   - Override ansible_connection from libvirt_qemu to ssh
   - Set ansible_host to IP addresses (192.168.122.x)

4. Updated Group Variables:
   - inventories/development/group_vars/kvm_guests.yml
   - Added ansible_connection: ssh to force SSH over libvirt
   - Maintains ProxyJump configuration through grokbox
   - SSH connection multiplexing settings preserved

5. Added .gitignore:
   - Exclude stats/ directory from version control
   - Prevents system_info role output from being committed

Dynamic Inventory Discovery:
- Automatically discovers VMs: pihole, mymx, derp
- Groups by state: running_vms, stopped_vms
- Groups by size: small_vms (≤2GB), medium_vms (2-8GB), large_vms (>8GB)
- Groups by OS: os_debian, os_unknown
- Creates UUID-based groups for unique identification

Connection Method:
- Discovery: libvirt plugin queries grokbox via SSH
- Execution: SSH with ProxyJump through grokbox
- Authentication: SSH keys (ansible user)
- Network: Private 192.168.122.0/24 via NAT

Testing Results:
 Dynamic inventory discovers all 3 VMs
 Groups created correctly (kvm_guests, running_vms, etc.)
 pihole: Connection successful via ProxyJump
⚠️  mymx, derp: SSH key authentication needed (not inventory issue)

Benefits:
- No manual inventory maintenance required
- VMs automatically added/removed based on libvirt state
- Dynamic grouping by resource allocation
- Centralized management through grokbox
- CLAUDE.md compliant (no static inventories in production-like envs)

Usage:
# List all discovered VMs
ansible-inventory -i inventories/development/ --graph

# Ping all KVM guests
ansible -i inventories/development/ kvm_guests -m ping

# Run playbook on running VMs
ansible-playbook -i inventories/development/ site.yml --limit running_vms

Migration Note:
The static inventory (hosts.yml) contained some hosts not managed
by libvirt (odin, seed). These external hosts need to be managed
via separate dynamic inventory sources or added back if required.

Related Documentation:
- docs/network-access-patterns.md (ProxyJump configuration)
- inventories/production/README.md (dynamic inventory examples)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-11 02:10:54 +01:00
parent 2ef8dfd6ed
commit cfad67a3a1
7 changed files with 34 additions and 122 deletions

1
.gitignore vendored
View File

@@ -36,3 +36,4 @@ credentials.yml
.pytest_cache/
.coverage
htmlcov/
stats/

View File

@@ -21,6 +21,8 @@ vm_gateway: "192.168.122.1"
# SSH & Connectivity
# -----------------------------------------------------------------------------
# Force SSH connection (override libvirt_qemu from dynamic inventory)
ansible_connection: ssh
ansible_user: ansible
ansible_become_password: null # Passwordless sudo configured

View File

@@ -0,0 +1,4 @@
---
# Override libvirt connection with SSH
ansible_connection: ssh
ansible_host: 192.168.122.99

View File

@@ -0,0 +1,4 @@
---
# Override libvirt connection with SSH
ansible_connection: ssh
ansible_host: 192.168.122.119

View File

@@ -0,0 +1,4 @@
---
# Override libvirt connection with SSH
ansible_connection: ssh
ansible_host: 192.168.122.12

View File

@@ -1,107 +0,0 @@
---
# =============================================================================
# Ansible Development Inventory
# =============================================================================
# Static/hybrid inventory for development environment
# Parsed from SSH config: ~/.ssh/config
# Generated: 2025-11-10
# =============================================================================
all:
children:
# External hosts accessible from public internet
external_hosts:
hosts:
odin:
ansible_host: 65.108.217.156
ansible_port: 22
ansible_user: user
ansible_python_interpreter: /usr/bin/python3
host_description: "External VPS Mail Server (Debian 13)"
host_role: mail_server
host_type: vps
os_family: Debian
os_version: "13"
# KVM/QEMU Hypervisors
hypervisors:
hosts:
grokbox:
ansible_host: grok.home.serneels.xyz
ansible_user: grok
ansible_python_interpreter: /usr/bin/python3
ansible_ssh_extra_args: '-o ForwardAgent=yes'
host_description: "Primary KVM hypervisor (libvirt 11.3.0)"
host_role: hypervisor
host_type: physical
hypervisor_type: kvm
libvirt_uri: "qemu:///system"
# KVM Guest Virtual Machines
kvm_guests:
vars:
# Common variables for all KVM guests
ansible_user: ansible
ansible_python_interpreter: /usr/bin/python3
ansible_ssh_common_args: '-o StrictHostKeyChecking=accept-new'
host_type: virtual_machine
hypervisor: grokbox
network: "virbr0 (192.168.122.0/24)"
children:
# DNS/DHCP Servers
dns_servers:
hosts:
pihole:
ansible_host: 192.168.122.12
ansible_ssh_common_args: '-o ProxyJump=grokbox -o StrictHostKeyChecking=accept-new'
host_description: "Pi-hole DNS/DHCP Server"
host_role: dns_server
vm_uuid: "6d714c93-16fb-41c8-8ef8-9001f9066b3a"
vm_vcpus: 2
vm_memory_mb: 2048
services:
- pihole
- dnsmasq
- lighttpd
autostart: true
# Mail Servers
mail_servers:
hosts:
mymx:
ansible_host: 192.168.122.119
ansible_ssh_common_args: '-o ProxyJump=grokbox -o StrictHostKeyChecking=accept-new'
host_description: "Local Mail Transfer Agent"
host_role: mail_server
vm_vcpus: 2
vm_memory_mb: 2048
services:
- postfix
- dovecot
autostart: true
# Development/Testing Hosts
development:
hosts:
derp:
ansible_host: 192.168.122.99
ansible_ssh_common_args: '-o ProxyJump=grokbox -o StrictHostKeyChecking=accept-new'
host_description: "General Purpose Development VM"
host_role: development
vm_uuid: "9ede717f-879b-48aa-add0-2dfd33e10765"
vm_vcpus: 2
vm_memory_mb: 2048
services:
- experimental
autostart: true
# Uncategorized/Discovery Hosts
uncategorized:
hosts:
seed:
ansible_host: 192.168.129.1
ansible_ssh_common_args: '-o StrictHostKeyChecking=accept-new'
host_description: "Host to be discovered"
host_role: unknown
discovery_status: pending

View File

@@ -11,9 +11,8 @@ plugin: community.libvirt.libvirt
# Hypervisor Connection
# -----------------------------------------------------------------------------
# URI to connect to libvirt hypervisor
# Local system: qemu:///system
# Remote SSH: qemu+ssh://user@host/system
uri: 'qemu:///system'
# Remote SSH connection to grokbox hypervisor
uri: 'qemu+ssh://grok@grok.home.serneels.xyz/system'
# Inventory Hostname Format
# -----------------------------------------------------------------------------
@@ -25,29 +24,34 @@ inventory_hostname: name
# -----------------------------------------------------------------------------
# Automatically create groups based on VM characteristics
compose:
# Set ansible_host from libvirt network IP if available
ansible_host: ansible_libvirt_ip_address | default(omit)
# Extract IP address from guest_info interface data
ansible_host: >-
guest_info['if.1.addr.0.addr'] if 'if.1.addr.0.addr' in guest_info else
(guest_info['if.0.addr.0.addr'] if 'if.0.addr.0.addr' in guest_info and guest_info['if.0.addr.0.addr'] != '127.0.0.1' else omit)
groups:
# Group by VM state
running_vms: ansible_libvirt_state == 'running'
stopped_vms: ansible_libvirt_state != 'running'
# Group by VM state (from info dict)
running_vms: info.state == 'running'
stopped_vms: info.state != 'running'
# Group by resource allocation
small_vms: ansible_libvirt_memory_mb <= 2048
medium_vms: ansible_libvirt_memory_mb > 2048 and ansible_libvirt_memory_mb <= 8192
large_vms: ansible_libvirt_memory_mb > 8192
# Group by resource allocation (convert KB to MB)
small_vms: (info.memory_kb | int / 1024) <= 2048
medium_vms: (info.memory_kb | int / 1024) > 2048 and (info.memory_kb | int / 1024) <= 8192
large_vms: (info.memory_kb | int / 1024) > 8192
# Group all discovered VMs as kvm_guests
kvm_guests: true
# Keyed Groups
# -----------------------------------------------------------------------------
# Create dynamic groups based on host variables
keyed_groups:
- key: ansible_libvirt_state
- key: info.state
prefix: state
separator: "_"
- key: ansible_libvirt_network
prefix: network
- key: guest_info['os.id'] | default('unknown')
prefix: os
separator: "_"
# Filters