152 lines
4.9 KiB
Python
152 lines
4.9 KiB
Python
#!/usr/bin/env python3
|
|
import docker
|
|
import requests
|
|
import socket
|
|
import netifaces
|
|
import os
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
CONFIG_PATH = "/etc/netbox-docker-sync.conf"
|
|
|
|
# === Konfigurationsdatei lesen ===
|
|
def read_config(filepath):
|
|
if not Path(filepath).is_file():
|
|
print(f"[FEHLER] Datei '{filepath}' nicht gefunden.")
|
|
sys.exit(1)
|
|
|
|
config = {}
|
|
try:
|
|
with open(filepath) as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if not line or line.startswith("#"):
|
|
continue
|
|
if "=" in line:
|
|
key, value = line.split("=", 1)
|
|
config[key.strip()] = value.strip()
|
|
except Exception as e:
|
|
print(f"[FEHLER] Fehler beim Lesen der Datei: {e}")
|
|
sys.exit(1)
|
|
|
|
# Pflichtfelder prüfen
|
|
required_keys = ["NETBOX_CLUSTER_ID", "NETBOX_URL", "NETBOX_TOKEN"]
|
|
for key in required_keys:
|
|
if key not in config or not config[key]:
|
|
print(f"[FEHLER] Konfigurationswert fehlt oder leer: {key}")
|
|
sys.exit(1)
|
|
|
|
# Cluster ID validieren
|
|
if not config["NETBOX_CLUSTER_ID"].isdigit():
|
|
print("[FEHLER] NETBOX_CLUSTER_ID ist keine gültige Zahl.")
|
|
sys.exit(1)
|
|
|
|
config["NETBOX_CLUSTER_ID"] = int(config["NETBOX_CLUSTER_ID"])
|
|
return config
|
|
|
|
# === Konfiguration laden ===
|
|
cfg = read_config(CONFIG_PATH)
|
|
CLUSTER_ID = cfg["NETBOX_CLUSTER_ID"]
|
|
NETBOX_URL = cfg["NETBOX_URL"]
|
|
NETBOX_TOKEN = cfg["NETBOX_TOKEN"]
|
|
|
|
NETBOX_HEADERS = {
|
|
"Authorization": f"Token {NETBOX_TOKEN}",
|
|
"Content-Type": "application/json",
|
|
"Accept": "application/json"
|
|
}
|
|
|
|
# === Standard-Netzwerkinterface automatisch ermitteln ===
|
|
def detect_default_interface():
|
|
try:
|
|
gws = netifaces.gateways()
|
|
return gws['default'][netifaces.AF_INET][1]
|
|
except Exception as e:
|
|
print(f"[!] Konnte Standard-Interface nicht ermitteln: {e}")
|
|
return "lo"
|
|
|
|
DOCKER_IFACE = os.environ.get("DOCKER_IFACE") or detect_default_interface()
|
|
|
|
# === IP-Adresse des Dockerhosts korrekt ermitteln ===
|
|
def get_host_ip():
|
|
try:
|
|
ip = netifaces.ifaddresses(DOCKER_IFACE)[netifaces.AF_INET][0]['addr']
|
|
if ip.startswith("127.") or ip == "":
|
|
raise ValueError("Ungültige IP-Adresse erkannt.")
|
|
return ip
|
|
except Exception as e:
|
|
print(f"[!] Konnte Host-IP über Interface {DOCKER_IFACE} nicht ermitteln: {e}")
|
|
return "0.0.0.0"
|
|
|
|
# Docker-Client initialisieren
|
|
client = docker.from_env()
|
|
DOCKER_HOSTNAME = socket.gethostname()
|
|
DOCKER_HOST_IP = get_host_ip()
|
|
|
|
# === Container erfassen und mit NetBox abgleichen ===
|
|
for container in client.containers.list():
|
|
name = container.name
|
|
image = container.image.tags[0] if container.image.tags else "unknown"
|
|
container_ip = container.attrs["NetworkSettings"]["IPAddress"]
|
|
|
|
# --- Hier Labels auslesen ---
|
|
labels = container.labels
|
|
project = labels.get("com.docker.compose.project", "")
|
|
service = labels.get("com.docker.compose.service", "")
|
|
version = labels.get("com.docker.compose.version", "")
|
|
|
|
# Exposed Ports auslesen (nur IPv4)
|
|
ports_raw = container.attrs["NetworkSettings"]["Ports"] or {}
|
|
exposed_ports = []
|
|
for port, mappings in ports_raw.items():
|
|
if mappings:
|
|
for mapping in mappings:
|
|
host_ip = mapping['HostIp']
|
|
if host_ip == "0.0.0.0" or host_ip.count(".") == 3:
|
|
exposed_ports.append(f"{host_ip}:{mapping['HostPort']} -> {port}")
|
|
else:
|
|
exposed_ports.append(f"(no mapping) -> {port}")
|
|
ports_string = ", ".join(exposed_ports)
|
|
|
|
print(f"[→] Verarbeite Container: {name} ({container_ip}) Ports: {ports_string}")
|
|
|
|
# Payload für NetBox-Eintrag
|
|
vm_payload = {
|
|
"name": name,
|
|
"status": "active",
|
|
"cluster": CLUSTER_ID,
|
|
"custom_fields": {
|
|
"container_ip": container_ip,
|
|
"docker_host": DOCKER_HOSTNAME,
|
|
"docker_host_ip": DOCKER_HOST_IP,
|
|
"docker_image": image,
|
|
"docker_ports": ports_string,
|
|
"compose_project": project,
|
|
"compose_service": service,
|
|
"stack_version": version
|
|
}
|
|
}
|
|
|
|
# Existiert die VM bereits in NetBox?
|
|
r = requests.get(
|
|
f"{NETBOX_URL}/virtualization/virtual-machines/?name={name}",
|
|
headers=NETBOX_HEADERS
|
|
)
|
|
|
|
if r.ok and r.json()["count"] > 0:
|
|
vm_id = r.json()["results"][0]["id"]
|
|
update = requests.patch(
|
|
f"{NETBOX_URL}/virtualization/virtual-machines/{vm_id}/",
|
|
headers=NETBOX_HEADERS,
|
|
json=vm_payload
|
|
)
|
|
print(f"[=] Aktualisiert: {name} ({update.status_code})")
|
|
else:
|
|
create = requests.post(
|
|
f"{NETBOX_URL}/virtualization/virtual-machines/",
|
|
headers=NETBOX_HEADERS,
|
|
json=vm_payload
|
|
)
|
|
print(f"[+] Erstellt: {name} ({create.status_code})")
|
|
|