diff --git a/nettrans-v1.py b/nettrans-v1.py deleted file mode 100644 index 91dd206..0000000 --- a/nettrans-v1.py +++ /dev/null @@ -1,259 +0,0 @@ -#!/usr/bin/env python3 -import os -import sys -import json -import zipfile -import subprocess -import shutil -import re -import time -from datetime import datetime - -# ========================================== -# Standard Konfiguration -# ========================================== -CONFIG = { - 'netbox_path': '/opt/netbox', - 'db_host': 'localhost', - 'db_name': 'netbox', - 'db_user': 'netbox', - 'db_pass': '', - 'backup_dir': '/tmp' -} - -# ========================================== -# Hilfsfunktionen für die Shell-GUI -# ========================================== -class Colors: - HEADER = '\033[95m' - BLUE = '\033[94m' - GREEN = '\033[92m' - WARNING = '\033[93m' - FAIL = '\033[91m' - ENDC = '\033[0m' - BOLD = '\033[1m' - -def clear_screen(): - os.system('clear' if os.name == 'posix' else 'cls') - -def print_header(title): - clear_screen() - print(Colors.HEADER + Colors.BOLD + "=" * 60 + Colors.ENDC) - print(Colors.HEADER + Colors.BOLD + f" {title}".ljust(59) + Colors.ENDC) - print(Colors.HEADER + Colors.BOLD + "=" * 60 + Colors.ENDC + "\n") - -def log_info(msg): - print(Colors.BLUE + f"[*] {msg}" + Colors.ENDC) - -def log_success(msg): - print(Colors.GREEN + Colors.BOLD + f"[+] {msg}" + Colors.ENDC) - -def log_error(msg): - print(Colors.FAIL + Colors.BOLD + f"[-] {msg}" + Colors.ENDC) - -def log_warn(msg): - print(Colors.WARNING + f"[!] {msg}" + Colors.ENDC) - -def pause(): - input(Colors.BOLD + "\nDrücke [ENTER], um ins Hauptmenü zurückzukehren..." + Colors.ENDC) - -# ========================================== -# Kernfunktionen: Backup & Restore -# ========================================== -def execute_backup(): - print_header("BACKUP PROZESS") - - media_path = os.path.join(CONFIG['netbox_path'], "netbox/media") - stamp = datetime.now().strftime("%Y%m%d_%H%M%S") - archive_name = f"netbox_full_backup_{stamp}" - zip_file_path = os.path.join(CONFIG['backup_dir'], f"{archive_name}.zip") - tmp_dir = os.path.join(CONFIG['backup_dir'], f"nb_tmp_{stamp}") - - os.makedirs(tmp_dir, exist_ok=True) - - try: - # 1. Datenbank-Dump - log_info("Schritt 1: Erstelle PostgreSQL Datenbank-Dump...") - dump_file = os.path.join(tmp_dir, "netbox_database.dump") - - env = os.environ.copy() - if CONFIG['db_pass']: env["PGPASSWORD"] = CONFIG['db_pass'] - - cmd = ["pg_dump", "-Fc", "-h", CONFIG['db_host'], "-U", CONFIG['db_user'], "-d", CONFIG['db_name'], "-f", dump_file] - process = subprocess.run(cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) - - if process.returncode != 0: - log_error(f"pg_dump fehlgeschlagen: {process.stderr}") - raise Exception("Datenbank-Backup fehlgeschlagen.") - log_success("PostgreSQL Dump erfolgreich erstellt.") - - # 2. Media-Dateien - log_info("Schritt 2: Kopiere Media-Dateien (Bilder, Dokumente)...") - if os.path.exists(media_path): - dst_media = os.path.join(tmp_dir, "media") - shutil.copytree(media_path, dst_media, dirs_exist_ok=True) - log_success("Media-Ordner erfolgreich gesichert.") - else: - log_warn(f"Kein Media-Verzeichnis unter {media_path} gefunden.") - - # 3. Metadaten - log_info("Schritt 3: Erstelle Metadaten...") - meta = {"version": "1.0", "timestamp": stamp, "source_db": CONFIG['db_name']} - with open(os.path.join(tmp_dir, "metadata.json"), "w") as f: - json.dump(meta, f, indent=4) - - # 4. ZIP erstellen - log_info(f"Schritt 4: Komprimiere Daten nach {zip_file_path} ...") - with zipfile.ZipFile(zip_file_path, 'w', zipfile.ZIP_DEFLATED) as zipf: - for root, _, files in os.walk(tmp_dir): - for file in files: - full_path = os.path.join(root, file) - rel_path = os.path.relpath(full_path, tmp_dir) - zipf.write(full_path, rel_path) - - print("\n" + "="*60) - log_success("BACKUP ERFOLGREICH ABGESCHLOSSEN!") - log_success(f"Datei liegt hier: {zip_file_path}") - print("="*60) - - except Exception as e: - log_error(f"Kritischer Fehler: {str(e)}") - finally: - if os.path.exists(tmp_dir): - shutil.rmtree(tmp_dir) - pause() - -def execute_restore(): - print_header("RESTORE PROZESS") - log_warn("ACHTUNG: Dieser Vorgang überschreibt die aktuelle Datenbank und das Media-Verzeichnis!") - confirm = input("Bist du sicher, dass du fortfahren möchtest? (j/N): ") - - if confirm.lower() != 'j': - log_info("Abbruch durch Benutzer.") - pause() - return - - restore_file = input(f"\nPfad zur Backup ZIP-Datei (z.B. /tmp/netbox_backup.zip): ").strip() - - if not restore_file or not os.path.exists(restore_file): - log_error(f"Die Datei '{restore_file}' existiert nicht!") - pause() - return - - media_path = os.path.join(CONFIG['netbox_path'], "netbox/media") - stamp = datetime.now().strftime("%Y%m%d_%H%M%S") - tmp_extract_dir = f"/tmp/nb_restore_{stamp}" - os.makedirs(tmp_extract_dir, exist_ok=True) - - try: - log_info(f"\nSchritt 1: Entpacke {restore_file} ...") - with zipfile.ZipFile(restore_file, 'r') as zipf: - zipf.extractall(tmp_extract_dir) - - if not os.path.exists(os.path.join(tmp_extract_dir, "metadata.json")): - raise Exception("Ungültiges Backup: metadata.json fehlt.") - - # 2. Datenbank Restore - log_info("Schritt 2: Stelle PostgreSQL Datenbank wieder her...") - dump_file = os.path.join(tmp_extract_dir, "netbox_database.dump") - env = os.environ.copy() - if CONFIG['db_pass']: env["PGPASSWORD"] = CONFIG['db_pass'] - - log_info("Lösche und erstelle Datenbank neu (Bereinigung)...") - subprocess.run(["dropdb", "-h", CONFIG['db_host'], "-U", CONFIG['db_user'], "--if-exists", CONFIG['db_name']], env=env, stderr=subprocess.PIPE) - subprocess.run(["createdb", "-h", CONFIG['db_host'], "-U", CONFIG['db_user'], "-O", CONFIG['db_user'], CONFIG['db_name']], env=env, stderr=subprocess.PIPE) - - log_info("Importiere Dump...") - subprocess.run(["pg_restore", "-h", CONFIG['db_host'], "-U", CONFIG['db_user'], "-d", CONFIG['db_name'], "--clean", "--no-owner", dump_file], env=env, stderr=subprocess.PIPE) - log_success("Datenbank erfolgreich wiederhergestellt.") - - # 3. Media Restore - log_info("Schritt 3: Stelle Media-Dateien wieder her...") - src_media = os.path.join(tmp_extract_dir, "media") - if os.path.exists(src_media): - if os.path.exists(media_path): shutil.rmtree(media_path) - shutil.copytree(src_media, media_path, dirs_exist_ok=True) - subprocess.run(["chown", "-R", "netbox:netbox", media_path], stderr=subprocess.PIPE) - log_success("Media-Dateien wiederhergestellt.") - - # 4. NetBox Upgrade - log_info("Schritt 4: Führe NetBox upgrade.sh aus (Cache-Clear & Migrations)...") - upgrade_script = os.path.join(CONFIG['netbox_path'], "upgrade.sh") - if os.path.exists(upgrade_script): - subprocess.run([upgrade_script], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - log_success("Upgrade-Skript durchgelaufen.") - - # 5. Services Restart - log_info("Schritt 5: Starte NetBox Dienste neu...") - subprocess.run(["systemctl", "restart", "netbox", "netbox-rq"], stderr=subprocess.PIPE) - - print("\n" + "="*60) - log_success("RESTORE ERFOLGREICH ABGESCHLOSSEN!") - print("="*60) - - except Exception as e: - log_error(f"Fehler beim Restore: {str(e)}") - finally: - if os.path.exists(tmp_extract_dir): - shutil.rmtree(tmp_extract_dir) - pause() - -def settings_menu(): - while True: - print_header("EINSTELLUNGEN") - keys = list(CONFIG.keys()) - for i, key in enumerate(keys, 1): - val = "*****" if key == 'db_pass' and CONFIG[key] else CONFIG[key] - print(f" {Colors.BOLD}{i}.{Colors.ENDC} {key.ljust(15)}: {Colors.BLUE}{val}{Colors.ENDC}") - - print(f"\n {Colors.BOLD}S.{Colors.ENDC} Speichern & Zurück zum Hauptmenü") - - choice = input("\nWelchen Wert möchtest du ändern? (Zahl/S): ").strip().lower() - - if choice == 's': - break - elif choice.isdigit() and 1 <= int(choice) <= len(keys): - key_to_edit = keys[int(choice)-1] - new_val = input(f"Neuer Wert für {key_to_edit} (aktuell: {CONFIG[key_to_edit]}): ") - if new_val.strip() != "": - CONFIG[key_to_edit] = new_val.strip() - -# ========================================== -# Hauptmenü -# ========================================== -def main_menu(): - while True: - print_header("NETBOX BACKUP & RESTORE TOOL") - print(f" {Colors.BOLD}1.{Colors.ENDC} Vollständiges Backup erstellen (DB + Media -> ZIP)") - print(f" {Colors.BOLD}2.{Colors.ENDC} Backup wiederherstellen (ZIP -> DB + Media)") - print(f" {Colors.BOLD}3.{Colors.ENDC} Einstellungen prüfen / anpassen") - print(f" {Colors.BOLD}4.{Colors.ENDC} Beenden\n") - - choice = input(Colors.BOLD + "Wähle eine Aktion (1-4): " + Colors.ENDC).strip() - - if choice == '1': - execute_backup() - elif choice == '2': - execute_restore() - elif choice == '3': - settings_menu() - elif choice == '4': - clear_screen() - print("Beendet. Auf Wiedersehen!\n") - sys.exit(0) - else: - log_error("Ungültige Eingabe.") - time.sleep(1) - -if __name__ == "__main__": - # Überprüfe auf Root-Rechte, da wir in /opt/netbox schreiben und systemctl nutzen - if os.geteuid() != 0: - print(Colors.WARNING + "Hinweis: Dieses Skript sollte idealerweise als 'root' oder mit 'sudo' ausgeführt werden," + Colors.ENDC) - print(Colors.WARNING + "da systemctl, chown und der Zugriff auf /opt/netbox erhöhte Rechte erfordern.\n" + Colors.ENDC) - time.sleep(2) - - try: - main_menu() - except KeyboardInterrupt: - print("\n\nAbbruch durch Benutzer. Ciao!") - sys.exit(0) \ No newline at end of file