Files
Analyse_Reseaux/gui_switch.py
2026-05-20 13:56:08 +02:00

679 lines
21 KiB
Python

import os
import sys
import subprocess
from datetime import datetime
from threading import Thread
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from pathlib import Path
def make_scrollable(parent):
canvas = tk.Canvas(parent, highlightthickness=0)
scrollbar = ttk.Scrollbar(parent, orient="vertical", command=canvas.yview)
scrollable_frame = ttk.Frame(canvas)
scrollable_frame.bind(
"<Configure>",
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
)
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
def on_configure(event):
canvas.itemconfig("frame", width=canvas.winfo_width())
canvas.create_window((0,0), window=scrollable_frame, anchor="nw", tags="frame")
canvas.bind("<Configure>", on_configure)
canvas.configure(yscrollcommand=scrollbar.set)
canvas.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")
canvas.bind_all("<MouseWheel>", lambda e: canvas.yview_scroll(int(-1*(e.delta/120)), "units"))
return scrollable_frame
class ToolTip:
def __init__(self, widget, text):
self.widget = widget
self.text = text
self.tipwindow = None
widget.bind("<Enter>", self.show)
widget.bind("<Leave>", self.hide)
def show(self, event=None):
if self.tipwindow or not self.text:
return
x = self.widget.winfo_rootx() + 20
y = self.widget.winfo_rooty() + 20
self.tipwindow = tw = tk.Toplevel(self.widget)
tw.wm_overrideredirect(True)
tw.wm_geometry(f"+{x}+{y}")
label = tk.Label(
tw,
text=self.text,
justify="left",
background="#ffffe0",
relief="solid",
borderwidth=1,
font=("Arial", 9),
padx=8,
pady=4
)
label.pack()
def hide(self, event=None):
if self.tipwindow:
self.tipwindow.destroy()
self.tipwindow = None
# Contenu fenêtre Analyse Switch Multi
def open_switch_gui_multi(app, OUTPUT_DIR, HELP_FILE_SW, SWITCH_DIR, SWITCH_MAIN):
app2 = tk.Toplevel(app)
app2.title("Analyse Configuration Switch - Plusieurs switch")
app2.geometry("800x450")
app2.resizable(True, True)
rapport_uplink = tk.BooleanVar()
schema_infra = tk.BooleanVar()
rapport_stack = tk.BooleanVar()
rapport_interfaces = tk.BooleanVar()
content = make_scrollable(app2)
def open_output_folder():
if sys.platform == "win32":
os.startfile(OUTPUT_DIR)
elif sys.platform == "darwin":
subprocess.run(["open", OUTPUT_DIR])
else:
subprocess.run(["xdg-open", OUTPUT_DIR])
def open_help():
if not os.path.exists(HELP_FILE_SW):
messagebox.showerror("Erreur", "Le fichier d'aide est introuvable.")
return
if sys.platform == "win32":
os.startfile(HELP_FILE_SW)
elif sys.platform == "darwin":
subprocess.run(["open", HELP_FILE_SW])
else:
subprocess.run(["xdg-open", HELP_FILE_SW])
def get_selected_switch(vars_dict):
for sw, var in vars_dict.items():
if var.get():
return sw
return None
def run_parser_multi():
selections = []
for name, vars_dict in file_selections.items():
sw = get_selected_switch(vars_dict)
if sw:
selections.append({
"type": "file",
"name": name,
"switch": sw
})
# for name, vars_dict in dir_selections.items():
# sw = get_selected_switch(vars_dict)
# if sw:
# selections.append({
# "type": "dir",
# "name": name,
# "switch": sw
# })
if not selections:
messagebox.showwarning(
"Aucune sélection",
"Veuillez sélectionner au moins un fichier ou dossier."
)
return
content.config(cursor="watch")
progress_bar = ttk.Progressbar(content, mode="indeterminate")
progress_bar.pack(pady=10, fill="x", padx=10)
progress_bar.start(10)
def process():
try:
for item in selections:
input_path = str(INPUT_DIR / item["name"])
cmd = [
sys.executable,
SWITCH_MAIN,
item["switch"],
input_path
]
if rapport_uplink.get():
cmd.append("-u")
if schema_infra.get():
cmd.append("-d")
if rapport_stack.get():
cmd.append("-s")
if rapport_interfaces.get():
cmd.append("-i")
cmd.append("-o")
if item["type"] == "file":
base_name = os.path.splitext(item["name"])[0]
cmd.append(base_name)
else:
cmd.append(item["name"])
print("Commande exécutée :", " ".join(cmd))
subprocess.run(cmd, cwd=SWITCH_DIR, check=True)
def on_success():
progress_bar.stop()
progress_bar.destroy()
content.config(cursor="")
messagebox.showinfo("Succès", "Tous les traitements sont terminés.")
open_output_folder()
app2.destroy()
app2.after(0, on_success)
except subprocess.CalledProcessError as e:
def on_error():
progress_bar.stop()
progress_bar.destroy()
content.config(cursor="")
messagebox.showerror(
"Erreur",
f"Erreur lors de l'exécution du traitement.\n\n{e}"
)
app2.after(0, on_error)
Thread(target=process, daemon=True).start()
def create_table(parent, title, items, mode):
"""
mode = 'file'
"""
style = ttk.Style()
style.configure(
"Table.TFrame",
background="white",
borderwidth=1,
relief="solid"
)
style.configure(
"Table.TLabel",
background="white"
)
style.configure(
"Table.TCheckbutton",
background="white"
)
style.map(
"Table.TCheckbutton",
background=[("disabled", "#f0f0f0")],
foreground=[("disabled", "#a0a0a0")]
)
ttk.Label(
parent,
text=title,
font=("Arial", 10, "bold")
).pack(anchor="w", padx=10, pady=(0, 4))
table = ttk.Frame(parent, style="Table.TFrame")
table.pack(fill="x", padx=10)
table.columnconfigure(0, weight=1)
if mode == "file": n = "Fichier source"
else : n = "Dossier source"
headers = [n, "HPE"]
for col, text in enumerate(headers):
ttk.Label(
table,
text=text,
style="Table.TLabel",
font=("Arial", 9, "bold")
).grid(row=0, column=col, padx=8, pady=6, sticky="e" if col > 0 else "w")
ttk.Separator(table, orient="horizontal").grid(
row=1, column=0, columnspan=4, sticky="ew", pady=(0, 2)
)
selections = {}
grid_row = 2
for name in items:
ttk.Label(
table,
text=name,
style="Table.TLabel"
).grid(row=grid_row, column=0, sticky="w", padx=8, pady=4)
var_hpe = tk.BooleanVar()
# var_autre = tk.BooleanVar()
def make_command(active, others):
def cmd():
if active.get():
for var in others:
var.set(False)
return cmd
cb_hpe = ttk.Checkbutton(
table,
variable=var_hpe,
style="Table.TCheckbutton",
command=make_command(var_hpe, [])
)
# cb_autre = ttk.Checkbutton(
# table,
# variable=var_autre,
# style="Table.TCheckbutton",
# command=make_command(var_autre, [var_hpe])
cb_hpe.grid(row=grid_row, column=1, sticky="n", padx=8)
# cb_autre.grid(row=grid_row, column=2, sticky="n", padx=8)
# elif mode == "file":
# cb_autre.state(["disabled"])
if mode == "dir":
cb_hpe.state(["disabled"])
selections[name] = {
"HPE": var_hpe,
# "autre": var_autre
}
# Séparateur interligne
ttk.Separator(table, orient="horizontal").grid(
row=grid_row + 1,
column=0,
columnspan=4,
sticky="ew"
)
grid_row += 2
return selections
INPUT_DIR = Path(OUTPUT_DIR).parent / "input"
if not INPUT_DIR.exists():
messagebox.showerror("Erreur", f"Dossier input introuvable : {INPUT_DIR}")
return
header_frame = ttk.Frame(content)
header_frame.pack(fill="x", padx=10, pady=5)
ttk.Button(
header_frame,
text="Help",
width=6,
command=open_help
).pack(side="right")
ttk.Label(
header_frame,
text="Génération de fichiers JSON au format normalisé YANG à partir des logs de plusieurs switches",
font=("Arial", 8, "bold")
).pack(side="left")
ttk.Label(
content,
text="/!\\ Mettre les fichiers/dossiers de configurations dans le dossier `./Parseurs_logs_Switch/src/input/`",
font=("Arial", 9, "italic"),
).pack(anchor="w", padx=10, pady=(0, 10))
ttk.Label(
content,
text="Sélectionnez les fichiers de configuration source à traiter :",
font=("Arial", 10)
).pack(anchor="w", padx=10)
files = [item.name for item in INPUT_DIR.iterdir() if item.is_file()]
# dirs = [item.name for item in INPUT_DIR.iterdir() if item.is_dir()]
file_selections = create_table(
content,
"🗎 Liste des fichiers de configuration source",
files,
mode="file"
)
# dir_selections = create_table(
# content,
# "🗁 Liste des dossiers de configuration source",
# dirs,
# mode="dir"
# )
ttk.Checkbutton(
content,
text="Générer le schéma d'infrastructure",
variable=schema_infra
).pack(anchor="w", padx=10, pady=(10, 0))
schema_infra.set(True)
ttk.Checkbutton(
content,
text="Générer le rapport des liens inter-switches en Excel",
variable=rapport_uplink
).pack(anchor="w", padx=10, pady=(0, 0))
rapport_uplink.set(True)
ttk.Checkbutton(
content,
text="Générer le rapport des stack en Excel",
variable=rapport_stack
).pack(anchor="w", padx=10, pady=(0, 0))
rapport_stack.set(True)
ttk.Checkbutton(
content,
text="Générer le rapport des interfaces en Excel",
variable=rapport_interfaces
).pack(anchor="w", padx=10, pady=(0, 10))
rapport_interfaces.set(True)
ttk.Label(
content,
text="Dossier de sortie :",
).pack(anchor="w", padx=10)
ttk.Button(
content,
text="Ouvrir le dossier de sortie",
command=open_output_folder
).pack(anchor="w", padx=10)
ttk.Button(
content,
text="Lancer le traitement",
command=run_parser_multi
).pack(pady=15)
content.mainloop()
# Contenu fenêtre Analyse Switch
def open_switch_gui(root, BASE_DIR):
SWITCH_DIR = os.path.join(
BASE_DIR,
"Parseurs_logs_Switch"
)
SWITCH_MAIN = os.path.join(
SWITCH_DIR,
"src",
"main.py"
)
HELP_FILE_SW = os.path.join(BASE_DIR, "help_Switch.md")
OUTPUT_DIR = os.path.join(SWITCH_DIR, "src", "output")
os.makedirs(OUTPUT_DIR, exist_ok=True)
app = tk.Toplevel(root)
app.title("Analyse Configuration Switch")
app.geometry("800x550")
app.resizable(True, True)
switch_var = tk.StringVar()
input_var = tk.StringVar()
output_var = tk.StringVar()
rapport_uplink = tk.BooleanVar()
schema_infra = tk.BooleanVar()
rapport_stack = tk.BooleanVar()
rapport_interfaces = tk.BooleanVar()
def browse_input():
sw_type = switch_var.get()
if sw_type == "":
messagebox.showerror("Erreur", "Veuillez d'abord sélectionner un type de switch.")
return
path = filedialog.askopenfilename(title="Sélectionnez le fichier d'entrée", parent=app)
input_var.set(path)
def update_output_label(*args):
if switch_var.get() == "":
output_label_var.set("Fichier de sortie :")
return
else :
sw = switch_var.get().lower()
if output_var.get():
s_json1 = os.path.join(OUTPUT_DIR, f"{sw}_current_{output_var.get()}.json")
s_json2 = os.path.join(OUTPUT_DIR, f"{sw}_saved_{output_var.get()}.json")
s_uplink = os.path.join(OUTPUT_DIR, f"rapport_uplink_{sw}_{output_var.get()}.xlsx")
s_stack = os.path.join(OUTPUT_DIR, f"rapport_stack_{sw}_{output_var.get()}.xlsx")
s_interfaces = os.path.join(OUTPUT_DIR, f"rapport_interfaces_{sw}_{output_var.get()}.xlsx")
s_schema = os.path.join(OUTPUT_DIR, f"schema_infra_{sw}_{output_var.get()}.xlsx")
else:
dt = datetime.now().strftime("%Y%m%d")
s_json1 = os.path.join(OUTPUT_DIR, f"{sw}_current_{dt}.json")
s_json2 = os.path.join(OUTPUT_DIR, f"{sw}_saved_{dt}.json")
s_uplink = os.path.join(OUTPUT_DIR, f"rapport_uplink_{sw}_{dt}.xlsx")
s_stack = os.path.join(OUTPUT_DIR, f"rapport_stack_{sw}_{dt}.xlsx")
s_interfaces = os.path.join(OUTPUT_DIR, f"rapport_interfaces_{sw}_{dt}.xlsx")
s_schema = os.path.join(OUTPUT_DIR, f"schema_infra_{sw}_{dt}.xlsx")
output_label_var.set("Fichier de sortie :\n" + s_json1 + "\n" + s_json2 + ("\n" + s_uplink if rapport_uplink.get() else "") + ("\n" + s_stack if rapport_stack.get() else "") + ("\n" + s_interfaces if rapport_interfaces.get() else "") + ("\n" + s_schema if schema_infra.get() else ""))
app.update_idletasks()
def open_output_folder():
if sys.platform == "win32":
os.startfile(OUTPUT_DIR)
elif sys.platform == "darwin":
subprocess.run(["open", OUTPUT_DIR])
else:
subprocess.run(["xdg-open", OUTPUT_DIR])
def open_help():
if not os.path.exists(HELP_FILE_SW):
messagebox.showerror("Erreur", "Le fichier d'aide est introuvable.")
return
if sys.platform == "win32":
os.startfile(HELP_FILE_SW)
elif sys.platform == "darwin":
subprocess.run(["open", HELP_FILE_SW])
else:
subprocess.run(["xdg-open", HELP_FILE_SW])
def run_parser():
if not switch_var.get():
messagebox.showerror("Erreur", "Veuillez sélectionner un type de switch.")
return
if not input_var.get():
messagebox.showerror("Erreur", "Veuillez sélectionner un fichier d'entrée.")
return
app.config(cursor="watch")
progress_bar = ttk.Progressbar(app, mode="indeterminate")
progress_bar.pack(pady=10, fill="x", padx=10)
progress_bar.start(10)
app.update_idletasks()
def process():
cmd = [
sys.executable,
SWITCH_MAIN,
switch_var.get(),
input_var.get()
]
if output_var.get():
cmd.extend(["-o", output_var.get()])
if rapport_uplink.get():
cmd.append("-u")
if schema_infra.get():
cmd.append("-d")
if rapport_stack.get():
cmd.append("-s")
if rapport_interfaces.get():
cmd.append("-i")
# print("Commande exécutée :", " ".join(cmd))
# print("Dossier courant (cwd) :", SWITCH_DIR)
try:
subprocess.run(
cmd,
cwd=SWITCH_DIR,
check=True
)
def on_success():
progress_bar.stop()
progress_bar.destroy()
app.config(cursor="")
messagebox.showinfo("Succès", "Traitement terminé avec succès.")
open_output_folder()
app.destroy()
app.after(0, on_success)
except subprocess.CalledProcessError as e:
def on_error():
progress_bar.stop()
progress_bar.destroy()
app.config(cursor="")
messagebox.showerror(
"Erreur",
f"Erreur lors de l'exécution du traitement.\n\n"
)
app.after(0, on_error)
Thread(target=process, daemon=True).start()
header_frame = ttk.Frame(app)
header_frame.pack(fill="x", padx=10, pady=5)
ttk.Button(
header_frame,
text="Help",
width=6,
command=open_help
).pack(side="right")
ttk.Label(
header_frame,
text="Génération d'un fichier JSON au format normalisé YANG à partir des logs d'un switch",
font=("Arial", 8, "bold")
).pack(side="left")
ttk.Button(
app,
text="Plusieurs Switches",
command=lambda: open_switch_gui_multi(app, OUTPUT_DIR, HELP_FILE_SW, SWITCH_DIR, SWITCH_MAIN)
).pack(anchor="w", padx=10)
ttk.Label(app, text="Type de switch").pack(anchor="w", padx=10, pady=5)
ttk.Combobox(
app,
values=["HPE"],
textvariable=switch_var,
state="readonly"
).pack(fill="x", padx=10)
input_label_var = tk.StringVar()
input_label_var.set("Fichier de logs source")
input_label_frame = ttk.Frame(app)
input_label_frame.pack(anchor="w", padx=5, pady=5)
info_label = ttk.Label(
input_label_frame,
text="",
cursor="hand2"
)
info_label.pack(side="right")
ttk.Label(
input_label_frame,
textvariable=input_label_var
).pack(side="left", padx=(5, 0))
ToolTip(
info_label,
"/!\\ Mettre le fichier/dossier de configurations\n"
"dans le dossier `/Parseurs_config_Firewall/src/input/` /!\\"
)
def update_input_label(*args):
switch_type = switch_var.get().lower()
input_label_var.set("Fichier de configuration source")
switch_var.trace_add("write", update_input_label)
input_frame = ttk.Frame(app)
input_frame.pack(fill="x", padx=10)
ttk.Entry(input_frame, textvariable=input_var).pack(side="left", fill="x", expand=True)
ttk.Button(input_frame, text="Parcourir", command=browse_input).pack(side="right")
ttk.Label(app, text="Nom de sortie (optionnel)").pack(anchor="w", padx=10, pady=5)
ttk.Entry(app, textvariable=output_var).pack(fill="x", padx=10)
ttk.Checkbutton(
app,
text="Générer le schéma d'infrastructure",
variable=schema_infra
).pack(anchor="w", padx=10, pady=(10, 0))
schema_infra.set(True)
ttk.Checkbutton(
app,
text="Générer le rapport des liens inter-switches en Excel",
variable=rapport_uplink
).pack(anchor="w", padx=10, pady=(0, 0))
rapport_uplink.set(True)
ttk.Checkbutton(
app,
text="Générer le rapport des stack en Excel",
variable=rapport_stack
).pack(anchor="w", padx=10, pady=(0, 0))
rapport_stack.set(True)
ttk.Checkbutton(
app,
text="Générer le rapport des interfaces en Excel",
variable=rapport_interfaces
).pack(anchor="w", padx=10, pady=(0, 10))
rapport_interfaces.set(True)
output_label_var = tk.StringVar()
ttk.Label(app, textvariable=output_label_var).pack(anchor="w", padx=10)
switch_var.trace_add("write", update_output_label)
output_var.trace_add("write", update_output_label)
schema_infra.trace_add("write", update_output_label)
rapport_uplink.trace_add("write", update_output_label)
rapport_stack.trace_add("write", update_output_label)
rapport_interfaces.trace_add("write", update_output_label)
update_output_label()
ttk.Button(
app,
text="Ouvrir le dossier de sortie",
command=open_output_folder
).pack(anchor="w", padx=10)
ttk.Button(
app,
text="Lancer le traitement",
command=run_parser
).pack(pady=15)
app.mainloop()