netbox-docker/backup/backup.py
s.farangi@limoo.host 36f888421e NetBox Docker backup
2025-12-18 19:05:12 +03:30

120 lines
3.4 KiB
Python

#!/usr/bin/env python3
import os
import tarfile
import subprocess
from ftplib import FTP
from dotenv import load_dotenv
from datetime import datetime
from pathlib import Path
import sys
# --------------------------------------------------
# Load environment variables
# --------------------------------------------------
ENV_FILE = os.getenv("BACKUP_ENV", "backup.env")
load_dotenv(ENV_FILE)
def required(var_name: str) -> str:
value = os.getenv(var_name)
if not value:
print(f"[ERROR] Missing required environment variable: {var_name}")
sys.exit(1)
return value
# --------------------------------------------------
# Required configuration
# --------------------------------------------------
FTP_SERVER = os.getenv("FTP_SERVER")
FTP_USER = os.getenv("FTP_USER")
FTP_PASSWORD = os.getenv("FTP_PASSWORD")
FTP_DIR = os.getenv("FTP_DIR", "/")
PG_USER = required("PG_USER")
PG_PASSWORD = required("PG_PASSWORD")
PG_DB = required("PG_DB")
PG_CONTAINER = required("PG_CONTAINER")
BACKUP_DIR = required("BACKUP_DIR")
NETBOX_VOLUME = required("NETBOX_VOLUME")
REPORTS_VOLUME = required("REPORTS_VOLUME")
# --------------------------------------------------
# Prepare paths & filenames
# --------------------------------------------------
DATE = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
Path(BACKUP_DIR).mkdir(parents=True, exist_ok=True)
NETBOX_BACKUP_FILE = f"{BACKUP_DIR}/netbox_media_{DATE}.tar.gz"
REPORTS_BACKUP_FILE = f"{BACKUP_DIR}/netbox_reports_{DATE}.tar.gz"
POSTGRES_BACKUP_FILE = f"{BACKUP_DIR}/postgres_{DATE}.sql.gz"
# --------------------------------------------------
# Helper functions
# --------------------------------------------------
def create_tar_gz(source: str, destination: str):
print(f"[INFO] Creating archive: {destination}")
with tarfile.open(destination, "w:gz") as tar:
tar.add(source, arcname=os.path.basename(source))
def backup_postgres():
print("[INFO] Backing up PostgreSQL database...")
command = (
f"docker exec {PG_CONTAINER} "
f"pg_dump -U {PG_USER} {PG_DB} | gzip"
)
with open(POSTGRES_BACKUP_FILE, "wb") as f:
subprocess.run(
command,
shell=True,
check=True,
env={**os.environ, "PGPASSWORD": PG_PASSWORD},
stdout=f,
)
def upload_to_ftp(local_file: str):
if not FTP_SERVER:
print("[INFO] FTP upload skipped (FTP_SERVER not set)")
return
print(f"[INFO] Uploading {os.path.basename(local_file)} to FTP...")
with FTP(FTP_SERVER) as ftp:
ftp.login(user=FTP_USER, passwd=FTP_PASSWORD)
ftp.cwd(FTP_DIR)
with open(local_file, "rb") as f:
ftp.storbinary(f"STOR {os.path.basename(local_file)}", f)
# --------------------------------------------------
# Main execution
# --------------------------------------------------
try:
print("[INFO] Starting NetBox backup process")
create_tar_gz(NETBOX_VOLUME, NETBOX_BACKUP_FILE)
create_tar_gz(REPORTS_VOLUME, REPORTS_BACKUP_FILE)
backup_postgres()
upload_to_ftp(NETBOX_BACKUP_FILE)
upload_to_ftp(REPORTS_BACKUP_FILE)
upload_to_ftp(POSTGRES_BACKUP_FILE)
print("[INFO] Backup completed successfully")
finally:
print("[INFO] Cleaning up local backup files")
for file in [
NETBOX_BACKUP_FILE,
REPORTS_BACKUP_FILE,
POSTGRES_BACKUP_FILE,
]:
if os.path.exists(file):
os.remove(file)