From e148b2fa21a54c0ddc87df88c434722cc9f29118 Mon Sep 17 00:00:00 2001 From: "LORENZO\\pacio" Date: Tue, 1 Jul 2025 17:00:00 +0200 Subject: [PATCH] init --- Dockerfile | 11 +++++ config.yaml | 21 ++++++++ docker-compose.yml | 9 ++++ requirements.txt | 3 ++ watcher.py | 119 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 163 insertions(+) create mode 100644 Dockerfile create mode 100644 config.yaml create mode 100644 docker-compose.yml create mode 100644 requirements.txt create mode 100644 watcher.py diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3a65e82 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM python:3.10-slim + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY watcher.py . +COPY config.yaml . + +CMD ["python", "-u", "watcher.py"] diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..d5ebf9c --- /dev/null +++ b/config.yaml @@ -0,0 +1,21 @@ +folders: + /mnt/tenants/ferrari: 20GB + /mnt/tenants/discovery: 20GB + /mnt/tenants/marrocco: 20GB + /mnt/tenants/unilab: 20GB + /mnt/tenants/lbdue: 20GB + +email: + smtp_server: relay.poloinformatico.it + smtp_port: 587 + username: brass@relay.poloinformatico.it + password: DMKqP9vUYn8s + to: paciotti@poloinformatico.it + from: brass@poloinformatico.it + +webui: + enabled: true + port: 8080 + +schedule: + seconds: 300 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..4539935 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +services: + folder-watcher: + build: . + ports: + - "48080:8080" + volumes: + - ./config.yaml:/app/config.yml + - /zucchetti/infinity:/mnt/tenants:ro + restart: unless-stopped diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6812e3d --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +flask +psutil +pyyaml diff --git a/watcher.py b/watcher.py new file mode 100644 index 0000000..4139bc5 --- /dev/null +++ b/watcher.py @@ -0,0 +1,119 @@ +import os +import smtplib +import yaml +import psutil +import threading +import time +from flask import Flask, render_template_string +from email.mime.text import MIMEText +import subprocess + +app = Flask(__name__) + +# Load configuration +try: + with open("config.yaml") as f: + config = yaml.safe_load(f) + print("[DEBUG] Loaded config.yaml successfully.") +except Exception as e: + print(f"[ERROR] Failed to load config.yaml: {e}") + exit(1) + +results = {} + +def get_folder_size(path): + print(f"[DEBUG] Calculating size for: {path}") + try: + out = subprocess.check_output(["du", "-sb", path], timeout=60) + size_bytes = int(out.decode().split()[0]) + print(f"[DEBUG] Total size for {path}: {size_bytes / 1e9:.2f} GB") + return size_bytes + except Exception as e: + print(f"[ERROR] Failed to get size for {path}: {e}") + return 0 + +def send_alert(folder, used, limit): + print(f"[ALERT] Sending email for {folder}: used={used}, limit={limit}") + try: + msg = MIMEText(f"Folder {folder} is over limit: {used / 1e9:.2f} GB used of {limit / 1e9:.2f} GB") + msg['Subject'] = f"[ALERT] Disk usage for {folder}" + msg['From'] = config['email']['from'] + msg['To'] = config['email']['to'] + + with smtplib.SMTP(config['email']['smtp_server'], config['email']['smtp_port']) as s: + s.starttls() + s.login(config['email']['username'], config['email']['password']) + s.send_message(msg) + print(f"[INFO] Email alert sent for {folder}") + except Exception as e: + print(f"[ERROR] Failed to send email alert: {e}") + +def check_folders(): + print("[INFO] Running folder usage check...") + new_results = {} + for folder, limit_str in config['folders'].items(): + if not os.path.exists(folder): + print(f"[WARN] Folder does not exist: {folder}") + continue + try: + limit = int(limit_str.replace("GB", "").strip()) * 1024 ** 3 + used = get_folder_size(folder) + exceeded = used > limit + new_results[folder] = { + "used_bytes": used, + "limit_bytes": limit, + "used_gb": used / (1024 ** 3), + "limit_gb": limit / (1024 ** 3), + "exceeded": exceeded + } + if exceeded: + send_alert(folder, used, limit) + except Exception as e: + print(f"[ERROR] Failed to check folder {folder}: {e}") + results.clear() + results.update(new_results) + +def schedule_check(interval_sec): + def loop(): + while True: + check_folders() + time.sleep(interval_sec) + t = threading.Thread(target=loop, daemon=True) + t.start() + +@app.route("/") +def index(): + html = """ + + Tenant Disk Usage + +

Tenant Folder Disk Usage (GB)

+ + + {% for folder, data in results.items() %} + + + + + + + {% endfor %} +
TenantUsed (GB)Limit (GB)Status
{{ folder }}{{ "%.2f"|format(data.used_gb) }}{{ "%.2f"|format(data.limit_gb) }}{{ 'Exceeded' if data.exceeded else 'OK' }}
+

Last updated: {{ now }}

+ + + """ + import datetime + return render_template_string(html, results=results, now=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')) + +if __name__ == "__main__": + interval = config.get("schedule", {}).get("seconds", 300) # default 5 minutes + print(f"[INFO] Starting scheduled checks every {interval} seconds.") + schedule_check(interval) + + if config.get("webui", {}).get("enabled", False): + port = config["webui"].get("port", 8080) + print(f"[INFO] Starting Flask Web UI on port {port}") + app.run(host="0.0.0.0", port=port) + else: + print("[INFO] Web UI disabled or missing from config.")