Dynamische Inventories generieren die Host-Liste zur Laufzeit durch ausführbare Skripte, anstatt statische Inventory-Dateien zu verwenden. Dies ist besonders vorteilhaft bei:
Ein dynamisches Inventory-Skript muss zwei Parameter unterstützen:
--list: Gibt das komplette Inventory als JSON aus--host <hostname>: Gibt host-spezifische
Variablen aus (optional)Das JSON-Format folgt der Ansible-Konvention für Gruppierung und Variablen.
inventory.sh:
#!/bin/bash
if [ "$1" = "--list" ]; then
cat << 'EOF'
{
"webservers": {
"hosts": ["web1.example.com", "web2.example.com"],
"vars": {
"http_port": 80,
"ssl_enabled": true
}
},
"databases": {
"hosts": ["db1.example.com", "db2.example.com"],
"vars": {
"mysql_port": 3306
}
}
}
EOF
elif [ "$1" = "--host" ]; then
echo '{}'
fiVerwendung:
chmod +x inventory.sh
ansible-playbook -i inventory.sh site.ymlinventory.py:
#!/usr/bin/env python3
import json
import sys
def build_inventory():
return {
'webservers': {
'hosts': ['web1.example.com', 'web2.example.com'],
'vars': {'http_port': 80}
},
'databases': {
'hosts': ['db1.example.com'],
'vars': {'mysql_port': 3306}
},
'_meta': {
'hostvars': {
'web1.example.com': {'ansible_host': '192.168.1.10'},
'web2.example.com': {'ansible_host': '192.168.1.11'},
'db1.example.com': {'ansible_host': '192.168.1.20'}
}
}
}
if __name__ == '__main__':
if len(sys.argv) == 2 and sys.argv[1] == '--list':
print(json.dumps(build_inventory(), indent=2))
elif len(sys.argv) == 3 and sys.argv[1] == '--host':
print('{}')
else:
sys.exit(1)servers.csv:
hostname,group,ip,environment
web1.example.com,webservers,192.168.1.10,production
web2.example.com,webservers,192.168.1.11,production
db1.example.com,databases,192.168.1.20,production
csv_inventory.py:
#!/usr/bin/env python3
import json
import csv
import sys
from collections import defaultdict
def load_from_csv(filename):
inventory = defaultdict(lambda: {'hosts': []})
hostvars = {}
with open(filename, 'r') as f:
for row in csv.DictReader(f):
group = row['group']
hostname = row['hostname']
inventory[group]['hosts'].append(hostname)
hostvars[hostname] = {
'ansible_host': row['ip'],
'environment': row['environment']
}
result = dict(inventory)
result['_meta'] = {'hostvars': hostvars}
return result
if __name__ == '__main__':
if len(sys.argv) == 2 and sys.argv[1] == '--list':
inventory = load_from_csv('servers.csv')
print(json.dumps(inventory, indent=2))
elif len(sys.argv) == 3 and sys.argv[1] == '--host':
print('{}')#!/usr/bin/env python3
import json
import sys
import requests
from urllib.parse import urljoin
class APIInventory:
def __init__(self, api_base):
self.api_base = api_base
def fetch_servers(self):
try:
url = urljoin(self.api_base, '/api/servers')
response = requests.get(url, timeout=10)
response.raise_for_status()
return response.json()
except requests.RequestException:
return []
def build_inventory(self):
servers = self.fetch_servers()
inventory = {'_meta': {'hostvars': {}}}
for server in servers:
group = server.get('role', 'ungrouped')
hostname = server['hostname']
if group not in inventory:
inventory[group] = {'hosts': []}
inventory[group]['hosts'].append(hostname)
inventory['_meta']['hostvars'][hostname] = {
'ansible_host': server['ip_address'],
'server_role': server['role'],
'environment': server.get('environment', 'unknown')
}
return inventory
if __name__ == '__main__':
if len(sys.argv) == 2 and sys.argv[1] == '--list':
api = APIInventory('https://cmdb.company.com')
inventory = api.build_inventory()
print(json.dumps(inventory, indent=2))
elif len(sys.argv) == 3 and sys.argv[1] == '--host':
print('{}')def create_dynamic_groups(servers):
inventory = {'_meta': {'hostvars': {}}}
for server in servers:
hostname = server['hostname']
# Basis-Gruppierung
role_group = f"role_{server['role']}"
env_group = f"env_{server['environment']}"
for group in [role_group, env_group]:
if group not in inventory:
inventory[group] = {'hosts': []}
inventory[group]['hosts'].append(hostname)
# Host-Variablen
inventory['_meta']['hostvars'][hostname] = {
'ansible_host': server['ip'],
'server_role': server['role'],
'environment': server['environment']
}
return inventory# JSON-Syntax validieren
./inventory.py --list | python3 -m json.tool
# Ansible-Validierung
ansible-inventory -i inventory.py --list
# Struktur visualisieren
ansible-inventory -i inventory.py --graph
# Verbindungstest
ansible -i inventory.py all -m ping --limit webserversBei größeren Umgebungen sollten Caching-Mechanismen implementiert werden:
import os
import time
import pickle
class CachedInventory:
def __init__(self, cache_file='/tmp/ansible_inventory.cache', ttl=300):
self.cache_file = cache_file
self.ttl = ttl
def get_cached_data(self):
if not os.path.exists(self.cache_file):
return None
if time.time() - os.path.getmtime(self.cache_file) > self.ttl:
return None
with open(self.cache_file, 'rb') as f:
return pickle.load(f)
def save_to_cache(self, data):
with open(self.cache_file, 'wb') as f:
pickle.dump(data, f)| Problem | Lösung |
|---|---|
| Skript nicht ausführbar | chmod +x inventory.py |
| Ungültiges JSON | Mit python3 -m json.tool testen |
| API-Timeouts | Timeout-Parameter setzen, Retry-Logik |
| Encoding-Probleme | UTF-8 explizit verwenden |
Dynamische Inventories bieten die Flexibilität, Ansible optimal in bestehende Infrastruktur-Landschaften zu integrieren, ohne auf externe Plugins angewiesen zu sein.