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( "", 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("", on_configure) canvas.configure(yscrollcommand=scrollbar.set) canvas.pack(side="left", fill="both", expand=True) scrollbar.pack(side="right", fill="y") canvas.bind_all("", 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("", self.show) widget.bind("", 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()