forked from JulieChv/Analyse_Reseaux
ajout doc + correction
This commit is contained in:
119
CREATE_FIREWALL_TOOL.md
Normal file
119
CREATE_FIREWALL_TOOL.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# Guide de Développement : Créer son propre outil Firewall
|
||||
|
||||
Ce guide explique comment étendre l'outil d'analyse réseau en ajoutant un nouveau outil pour les firewalls.
|
||||
|
||||
> **Note :** Tout au long de ce guide, remplacez **`OUTIL`** (en majuscule ou minuscule) par le nom de l'outil que vous souhaitez développer'.
|
||||
|
||||
---
|
||||
|
||||
## Étape 1 : Création du script de l'outil
|
||||
|
||||
Dans le dossier `Parseurs_config_Firewall/src/scripts/` (ou `script/` selon votre arborescence), créez un nouveau fichier Python nommé **`export_OUTIL.py`**.
|
||||
|
||||
*Il est fortement recommandé de s'inspirer des parseurs existants comme `export_matrice_routage.py`, `export_matrice_flux.py` ou `export_interfaces.py`.*
|
||||
|
||||
Voici le squelette de code à utiliser :
|
||||
|
||||
```python
|
||||
def export_to_excel(json_file_path, output_file_excel):
|
||||
"""
|
||||
Export firewall data from JSON to Excel
|
||||
Args:
|
||||
json_file_path: Path to the JSON file to process
|
||||
output_file_excel: Path to the output Excel file
|
||||
"""
|
||||
|
||||
# Votre code
|
||||
```
|
||||
|
||||
## Étape 2 : Intégration dans le moteur principal (`main.py`)
|
||||
|
||||
Pour que le script global prenne en charge le nouveau modèle, ouvrez le fichier `Parseurs_config_Firewall/src/main.py` :
|
||||
|
||||
1. Importez votre nouvelle fonction en haut du fichier :
|
||||
```python
|
||||
from scripts.export_OUTIL import export_to_excel as export_OUTIL_to_excel
|
||||
```
|
||||
|
||||
2. Ajoutez la condition correspondante dans le bloc de sélection de l'outil :
|
||||
```python
|
||||
if "-X" in sys.argv:
|
||||
print(f"\nGénération de l'export les OUTIL...")
|
||||
if "-o" in sys.argv:
|
||||
o_index = sys.argv.index("-o")
|
||||
if o_index + 1 < len(sys.argv):
|
||||
output_file_excel = os.path.join(f"{output_path}OUTIL_{firewall_type}_{sys.argv[o_index + 1]}.xlsx")
|
||||
else:
|
||||
print("Erreur: nom de fichier de sortie manquant après '-o'.")
|
||||
sys.exit(1)
|
||||
else:
|
||||
timestamp = time.strftime("%Y%m%d")
|
||||
output_file_excel = f"{output_path}OUTIL_{firewall_type}_{timestamp}.xlsx"
|
||||
output_file_excel = verify_if_file_exists(output_file_excel)
|
||||
excel_file = export_OUTIL_to_excel(output_file_json, output_file_excel)
|
||||
print(f"✓ Processus terminé. Fichiers générés:\n - JSON: {output_file_json}\n - Excel: {excel_file}")
|
||||
```
|
||||
> **Note :** Remplacez **`X`** de la première ligne par la lettre souhaitez (en dehors de celles déjà existante [o,f,r,i])'.
|
||||
|
||||
3. Mettez à jour les instructions textuelles d'usage affichées dans la console si le paramètre saisi est incorrect afin d'inclure `"OUTIL"` dans la liste des choix valides.
|
||||
```python
|
||||
print(" -X Generate OUTIL report (optional)")
|
||||
```
|
||||
> **Note :** Remplacez **`X`** par la lettre précédemmment choisi'.
|
||||
|
||||
|
||||
## Étape 3 : Adaptation de l'Interface Graphique (GUI)
|
||||
|
||||
Afin que le nouveau modèle apparaisse dans l'interface graphique unifiée :
|
||||
|
||||
1. Ouvrez le fichier de gestion de la GUI (`gui_firewall.py` racine ou script GUI dédié).
|
||||
2. Dans la fonction `open_firewall_gui_multi` :
|
||||
|
||||
- Ajouter la variable :
|
||||
```python
|
||||
OUTIL = tk.BooleanVar()
|
||||
```
|
||||
|
||||
- Dans la fonction `process()`, ajouter :
|
||||
```python
|
||||
if OUTIL.get():
|
||||
cmd.append("-X")
|
||||
```
|
||||
|
||||
- Ajouter égalemment dans la fonction `open_firewall_gui_multi`, le bouton de sélection de l'outil avec les autres existant :
|
||||
```python
|
||||
ttk.Checkbutton(
|
||||
content,
|
||||
text="Description courte de l'outil",
|
||||
variable=OUTIL
|
||||
).pack(anchor="w", padx=10, pady=(0, 0))
|
||||
OUTIL.set(True)
|
||||
```
|
||||
|
||||
3. Dans la fonction `open_firewall_gui` :
|
||||
|
||||
- Répéter les mêmes opérations que pour `open_firewall_gui_multi`
|
||||
- Dans la fonction `update_output_label(*args)` ajouter et modifier les éléments suivants :
|
||||
```python
|
||||
def update_output_label(*args):
|
||||
...
|
||||
if output_var.get(): #ligne déjà existante
|
||||
f_OUTIL = os.path.join(OUTPUT_DIR, f"OUTIL_{fw}_{output_var.get()}.xlsx")
|
||||
...
|
||||
else :
|
||||
f_OUTIL = os.path.join(OUTPUT_DIR, f"OUTIL_{fw}_{dt}.xlsx")
|
||||
...
|
||||
|
||||
output_label_var.set("Fichier de sortie :\n" + f_json + ("\n" + f_flux if matrice_flux.get() else "") + ("\n" + f_routage if matrice_routage.get() else "") + ("\n" + f_interfaces if interfaces.get() else "") + ("\n" + f_OUTIL if OUTIL.get() else "")) #ligne déjà existante a modifier
|
||||
```
|
||||
- Ajouter vers la fin de la fonction `open_firewall_gui` avec les autres existant :
|
||||
```python
|
||||
OUTIL.trace_add("write", update_output_label)
|
||||
```
|
||||
|
||||
4. Ouvrez le fichier de gestion principale de la GUI (`main.py` racine ou script GUI dédié).
|
||||
|
||||
- Dans la fonction `open_main_gui()` ajouter dans le Label du Firewall :
|
||||
```python
|
||||
"\n + possibilité de générer un rapport des OUTIL",
|
||||
```
|
||||
@@ -404,7 +404,7 @@ Pour que le script global prenne en charge le nouveau modèle, ouvrez le fichier
|
||||
import scripts.json_modele as json_modele
|
||||
```
|
||||
|
||||
2. Ajoutez la condition correspondante dans le bloc de sélection du type de firewall :
|
||||
2. Ajoutez la condition correspondante dans le bloc de sélection du type de switch :
|
||||
```python
|
||||
elif switch_type == "modele":
|
||||
json_modele.generate_json_modele(input_data, output_file1_json, output_file2_json)
|
||||
|
||||
119
CREATE_SWITCH_TOOL.md
Normal file
119
CREATE_SWITCH_TOOL.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# Guide de Développement : Créer son propre outil Switch
|
||||
|
||||
Ce guide explique comment étendre l'outil d'analyse réseau en ajoutant un nouveau outil pour les switches.
|
||||
|
||||
> **Note :** Tout au long de ce guide, remplacez **`OUTIL`** (en majuscule ou minuscule) par le nom de l'outil que vous souhaitez développer'.
|
||||
|
||||
---
|
||||
|
||||
## Étape 1 : Création du script de l'outil
|
||||
|
||||
Dans le dossier `Parseurs_logs_Switch/src/scripts/` (ou `script/` selon votre arborescence), créez un nouveau fichier Python nommé **`export_OUTIL.py`**.
|
||||
|
||||
*Il est fortement recommandé de s'inspirer des parseurs existants comme `export_rapport_stack.py`, `export_rapport_interfaces.py`, `export_rapport_uplink.py` ou `export_schema_infra.py`.*
|
||||
|
||||
Voici le squelette de code à utiliser :
|
||||
|
||||
```python
|
||||
def main(output_dir, output_file)
|
||||
"""
|
||||
Export switch data from JSON to Excel
|
||||
Args:
|
||||
json_file_path: Path to the JSON file to process
|
||||
output_file: Path to the output Excel file
|
||||
"""
|
||||
|
||||
# Votre code
|
||||
```
|
||||
|
||||
## Étape 2 : Intégration dans le moteur principal (`main.py`)
|
||||
|
||||
Pour que le script global prenne en charge le nouveau modèle, ouvrez le fichier `Parseurs_logs_Switch/src/main.py` :
|
||||
|
||||
1. Importez votre nouvelle fonction en haut du fichier :
|
||||
```python
|
||||
from scripts.export_OUTIL import main as rapport_OUTIL
|
||||
```
|
||||
|
||||
2. Ajoutez la condition correspondante dans le bloc de sélection de l'outil :
|
||||
```python
|
||||
if "-X" in sys.argv:
|
||||
print(f"\nGénération de OUTIL...")
|
||||
if "-o" in sys.argv:
|
||||
o_index = sys.argv.index("-o")
|
||||
if o_index + 1 < len(sys.argv):
|
||||
output_file_html = os.path.join(f"{output_path}OUTIL_{switch_type}_{sys.argv[o_index + 1]}.html")
|
||||
else:
|
||||
print("Erreur: nom de fichier de sortie manquant après '-o'.")
|
||||
sys.exit(1)
|
||||
else:
|
||||
timestamp = time.strftime("%Y%m%d")
|
||||
output_file_html = f"{output_path}OUTIL_{switch_type}_{timestamp}.html"
|
||||
output_file_html = verify_if_file_exists(output_file_html)
|
||||
html_file = OUTIL(output_path, output_file_html)
|
||||
print(f"✓ Processus terminé. Fichiers générés:\n - JSON: {output_file1_json} & {output_file2_json}\n - HTML: {html_file}")
|
||||
```
|
||||
> **Note :** Remplacez **`X`** de la première ligne par la lettre souhaitez (en dehors de celles déjà existante [o,d,u,s,i])'.
|
||||
|
||||
3. Mettez à jour les instructions textuelles d'usage affichées dans la console si le paramètre saisi est incorrect afin d'inclure `"OUTIL"` dans la liste des choix valides.
|
||||
```python
|
||||
print(" -X Generate OUTIL report (optional)")
|
||||
```
|
||||
> **Note :** Remplacez **`X`** par la lettre précédemmment choisi'.
|
||||
|
||||
|
||||
## Étape 3 : Adaptation de l'Interface Graphique (GUI)
|
||||
|
||||
Afin que le nouveau modèle apparaisse dans l'interface graphique unifiée :
|
||||
|
||||
1. Ouvrez le fichier de gestion de la GUI (`gui_switch.py` racine ou script GUI dédié).
|
||||
2. Dans la fonction `open_switch_gui_multi` :
|
||||
|
||||
- Ajouter la variable :
|
||||
```python
|
||||
OUTIL = tk.BooleanVar()
|
||||
```
|
||||
|
||||
- Dans la fonction `process()`, ajouter :
|
||||
```python
|
||||
if OUTIL.get():
|
||||
cmd.append("-X")
|
||||
```
|
||||
|
||||
- Ajouter égalemment dans la fonction `open_switch_gui_multi`, le bouton de sélection de l'outil avec les autres existant :
|
||||
```python
|
||||
ttk.Checkbutton(
|
||||
content,
|
||||
text="Description courte de l'outil",
|
||||
variable=OUTIL
|
||||
).pack(anchor="w", padx=10, pady=(0, 0))
|
||||
OUTIL.set(True)
|
||||
```
|
||||
|
||||
3. Dans la fonction `open_switch_gui` :
|
||||
|
||||
- Répéter les mêmes opérations que pour `open_switch_gui_multi`
|
||||
- Dans la fonction `update_output_label(*args)` ajouter et modifier les éléments suivants :
|
||||
```python
|
||||
def update_output_label(*args):
|
||||
...
|
||||
if output_var.get(): #ligne déjà existante
|
||||
f_OUTIL = os.path.join(OUTPUT_DIR, f"OUTIL_{fw}_{output_var.get()}.xlsx")
|
||||
...
|
||||
else :
|
||||
f_OUTIL = os.path.join(OUTPUT_DIR, f"OUTIL_{fw}_{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 "") + ("\n" + f_OUTIL if OUTIL.get() else "")) #ligne déjà existante a modifier
|
||||
```
|
||||
- Ajouter vers la fin de la fonction `open_switch_gui` avec les autres existant :
|
||||
```python
|
||||
OUTIL.trace_add("write", update_output_label)
|
||||
```
|
||||
|
||||
4. Ouvrez le fichier de gestion principale de la GUI (`main.py` racine ou script GUI dédié).
|
||||
|
||||
- Dans la fonction `open_main_gui()` ajouter dans le Label du Switch :
|
||||
```python
|
||||
"\n + possibilité de générer un rapport des OUTIL",
|
||||
```
|
||||
BIN
Computacenter_logo.png
Normal file
BIN
Computacenter_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
@@ -6,6 +6,7 @@ Cet outil permet de **parser les configurations de différents types de firewall
|
||||
|
||||
- Il fournit également la possibilité de générer une **matrice de flux au format Excel** pour visualiser les communications et règles de trafic dans l’infrastructure.
|
||||
- Il founit également la possibilité de générer une **matrice de routage au format Excel** pour visualiser les routes statiques dans l’infrastructure.
|
||||
- Il founit également la possibilité de générer le **détail des interfaces au format Excel** pour visualiser la configuration des interfaces.
|
||||
|
||||
## Fonctionnalités principales
|
||||
|
||||
@@ -46,6 +47,10 @@ Cet outil permet de **parser les configurations de différents types de firewall
|
||||
- Script Python qui utilise le JSON normalisé pour générer automatiquement une matrice Excel détaillant :
|
||||
- les routes statiques
|
||||
|
||||
7. **Génération des interfaces**
|
||||
- Script Python qui utilise le JSON normalisé pour générer automatiquement une matrice Excel détaillant :
|
||||
- la configuration des interfaces
|
||||
|
||||
## Utilisation
|
||||
|
||||
### Pré-requis
|
||||
@@ -59,9 +64,9 @@ pip install -r .\src\requirements.txt
|
||||
|
||||
#### Commandes principales
|
||||
```bash
|
||||
python3 .\src\main.py stormshield .\src\input\backup\ -f -r
|
||||
python3 .\src\main.py paloalto .\src\input\nomfichier -f -r
|
||||
python3 .\src\main.py forcepoint .\src\input\nomfichier -f -r
|
||||
python3 .\src\main.py stormshield .\src\input\backup\ -f -r -i
|
||||
python3 .\src\main.py paloalto .\src\input\nomfichier -f -r -i
|
||||
python3 .\src\main.py forcepoint .\src\input\nomfichier -f -r -i
|
||||
```
|
||||
#### Options
|
||||
|
||||
@@ -70,6 +75,8 @@ python3 .\src\main.py forcepoint .\src\input\nomfichier -f -r
|
||||
| -o [nom_fichier] | Spécifie le nom du fichier JSON de sortie (optionnel)
|
||||
| -f | Génère un rapport Excel de type matrice de flux (optionnel)
|
||||
| -r | Génère un rapport Excel de type matrice de routage (optionnel)
|
||||
| -i | Generate interface report (optional)
|
||||
|
||||
---
|
||||
|
||||
## Arborescence du projet
|
||||
|
||||
@@ -6,6 +6,7 @@ from scripts.json_Stormshield import generate_json_stormshield
|
||||
from scripts.json_Forcepoint import generate_json_forcepoint
|
||||
from scripts.export_matrice_flux import export_to_excel as export_flux_to_excel
|
||||
from scripts.export_matrice_routage import export_to_excel as export_routing_to_excel
|
||||
from scripts.export_interfaces import export_to_excel as export_interfaces_to_excel
|
||||
|
||||
def verify_if_file_exists(name):
|
||||
base, ext = os.path.splitext(name)
|
||||
@@ -24,6 +25,7 @@ def main():
|
||||
print(" -o <output_file> Specify output JSON file name (optional)")
|
||||
print(" -f Generate matrix flux report (optional)")
|
||||
print(" -r Generate routing matrix report (optional)")
|
||||
print(" -i Generate interface report (optional)")
|
||||
sys.exit(1)
|
||||
|
||||
firewall_type = sys.argv[1].lower()
|
||||
@@ -85,5 +87,21 @@ def main():
|
||||
excel_file = export_routing_to_excel(output_file_json, output_file_excel)
|
||||
print(f"✓ Processus terminé. Fichiers générés:\n - JSON: {output_file_json}\n - Excel: {excel_file}")
|
||||
|
||||
if "-i" in sys.argv:
|
||||
print(f"\nGénération de l'export les interfaces...")
|
||||
if "-o" in sys.argv:
|
||||
o_index = sys.argv.index("-o")
|
||||
if o_index + 1 < len(sys.argv):
|
||||
output_file_excel = os.path.join(f"{output_path}interfaces_{firewall_type}_{sys.argv[o_index + 1]}.xlsx")
|
||||
else:
|
||||
print("Erreur: nom de fichier de sortie manquant après '-o'.")
|
||||
sys.exit(1)
|
||||
else:
|
||||
timestamp = time.strftime("%Y%m%d")
|
||||
output_file_excel = f"{output_path}interfaces_{firewall_type}_{timestamp}.xlsx"
|
||||
output_file_excel = verify_if_file_exists(output_file_excel)
|
||||
excel_file = export_interfaces_to_excel(output_file_json, output_file_excel)
|
||||
print(f"✓ Processus terminé. Fichiers générés:\n - JSON: {output_file_json}\n - Excel: {excel_file}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
201
Parseurs_config_Firewall/src/scripts/export_interfaces.py
Normal file
201
Parseurs_config_Firewall/src/scripts/export_interfaces.py
Normal file
@@ -0,0 +1,201 @@
|
||||
import json
|
||||
import pandas as pd
|
||||
from openpyxl import load_workbook
|
||||
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
|
||||
from openpyxl.utils import get_column_letter
|
||||
|
||||
|
||||
center = Alignment(horizontal="center", vertical="center", wrap_text=True)
|
||||
left = Alignment(horizontal="left", vertical="center", wrap_text=True)
|
||||
|
||||
header_fill = PatternFill(start_color="2F5496", fill_type="solid")
|
||||
iface_fill = PatternFill(start_color="BDD7EE", fill_type="solid")
|
||||
sub_fill = PatternFill(start_color="DDEBF7", fill_type="solid")
|
||||
disabled_fill= PatternFill(start_color="F2F2F2", fill_type="solid")
|
||||
|
||||
thick_border = Border(*(Side(style="thick"),)*4)
|
||||
thin_border = Border(*(Side(style="thin"),)*4)
|
||||
medium_side = Side(style="medium")
|
||||
|
||||
|
||||
def _thin(top=False, bottom=False, left_s=False, right_s=False):
|
||||
return Border(
|
||||
top=Side(style="thin") if top else Side(style=None),
|
||||
bottom=Side(style="thin") if bottom else Side(style=None),
|
||||
left=Side(style="thin") if left_s else Side(style=None),
|
||||
right=Side(style="thin") if right_s else Side(style=None),
|
||||
)
|
||||
|
||||
|
||||
def _build_vrf_map(data):
|
||||
"""Retourne {interface_name: vrf_name} depuis network-instances."""
|
||||
vrf_map = {}
|
||||
for ni in data.get("openconfig-network-instance:network-instances", {}).get("network-instance", []):
|
||||
vrf_name = ni.get("name", "")
|
||||
for iface in ni.get("interfaces", {}).get("interface", []):
|
||||
iface_id = iface.get("id", "")
|
||||
if iface_id:
|
||||
vrf_map[iface_id] = vrf_name
|
||||
return vrf_map
|
||||
|
||||
|
||||
def _parse_interfaces(data):
|
||||
vrf_map = _build_vrf_map(data)
|
||||
rows = []
|
||||
|
||||
for iface in data.get("openconfig-interfaces:interfaces", {}).get("interface", []):
|
||||
cfg = iface.get("config", {})
|
||||
iface_name = cfg.get("name", iface.get("name", ""))
|
||||
iface_type = cfg.get("type", "")
|
||||
iface_desc = cfg.get("description", "")
|
||||
enabled = cfg.get("enabled", True)
|
||||
|
||||
subinterfaces = iface.get("subinterfaces", {}).get("subinterface", [])
|
||||
|
||||
if not subinterfaces:
|
||||
rows.append({
|
||||
"Interface": iface_name,
|
||||
"Type": iface_type,
|
||||
"Description": iface_desc,
|
||||
"Enabled": "Oui" if enabled else "Non",
|
||||
"VLAN": "",
|
||||
"IP": "",
|
||||
"Préfixe": "",
|
||||
"VRF": vrf_map.get(iface_name, ""),
|
||||
"_is_sub": False,
|
||||
})
|
||||
else:
|
||||
for sub in subinterfaces:
|
||||
sub_cfg = sub.get("config", {})
|
||||
vlan = sub.get("index", sub_cfg.get("index", ""))
|
||||
sub_name = f"{iface_name}.{vlan}" if vlan != 0 else iface_name
|
||||
sub_enabled = sub_cfg.get("enabled", enabled)
|
||||
|
||||
addresses = (
|
||||
sub.get("oc-ip:ipv4", {})
|
||||
.get("oc-ip:addresses", {})
|
||||
.get("oc-ip:address", [])
|
||||
)
|
||||
|
||||
if not addresses:
|
||||
rows.append({
|
||||
"Interface": iface_name,
|
||||
"Type": iface_type,
|
||||
"Description": iface_desc,
|
||||
"Enabled": "Oui" if sub_enabled else "Non",
|
||||
"VLAN": "" if vlan == 0 else vlan,
|
||||
"IP": "",
|
||||
"Préfixe": "",
|
||||
"VRF": vrf_map.get(sub_name, vrf_map.get(iface_name, "")),
|
||||
"_is_sub": vlan != 0,
|
||||
})
|
||||
else:
|
||||
for addr in addresses:
|
||||
addr_cfg = addr.get("oc-ip:config", {})
|
||||
rows.append({
|
||||
"Interface": iface_name,
|
||||
"Type": iface_type,
|
||||
"Description": iface_desc,
|
||||
"Enabled": "Oui" if sub_enabled else "Non",
|
||||
"VLAN": "" if vlan == 0 else vlan,
|
||||
"IP": addr_cfg.get("oc-ip:ip", ""),
|
||||
"Préfixe": addr_cfg.get("oc-ip:prefix-length", ""),
|
||||
"VRF": vrf_map.get(sub_name, vrf_map.get(iface_name, "")),
|
||||
"_is_sub": vlan != 0,
|
||||
})
|
||||
|
||||
return rows
|
||||
|
||||
|
||||
|
||||
def _style_interfaces(ws):
|
||||
COLS = {
|
||||
"Interface": 1,
|
||||
"Type": 2,
|
||||
"Description": 3,
|
||||
"Enabled": 4,
|
||||
"VLAN": 5,
|
||||
"IP": 6,
|
||||
"Préfixe": 7,
|
||||
"VRF": 8,
|
||||
}
|
||||
N = len(COLS)
|
||||
|
||||
for col in range(1, N + 1):
|
||||
cell = ws.cell(row=1, column=col)
|
||||
cell.fill = header_fill
|
||||
cell.font = Font(bold=True, color="FFFFFF", size=10)
|
||||
cell.alignment = center
|
||||
cell.border = thin_border
|
||||
|
||||
ws.freeze_panes = "A2"
|
||||
|
||||
max_width = {c: len(str(ws.cell(row=1, column=c).value or "")) for c in range(1, N + 1)}
|
||||
|
||||
prev_iface = None
|
||||
group_start = 2
|
||||
|
||||
for row in range(2, ws.max_row + 1):
|
||||
iface_val = ws.cell(row=row, column=COLS["Interface"]).value
|
||||
enabled = ws.cell(row=row, column=COLS["Enabled"]).value
|
||||
is_last = (row == ws.max_row)
|
||||
next_iface = ws.cell(row=row + 1, column=COLS["Interface"]).value if not is_last else None
|
||||
|
||||
if enabled == "Non":
|
||||
row_fill = disabled_fill
|
||||
elif ws.cell(row=row, column=COLS["VLAN"]).value:
|
||||
row_fill = sub_fill
|
||||
else:
|
||||
row_fill = iface_fill
|
||||
|
||||
for col in range(1, N + 1):
|
||||
cell = ws.cell(row=row, column=col)
|
||||
if col != COLS["Interface"]:
|
||||
cell.fill = row_fill
|
||||
cell.alignment = left if col not in (COLS["Enabled"], COLS["VLAN"], COLS["Préfixe"]) else center
|
||||
cell.border = thin_border
|
||||
|
||||
val = cell.value
|
||||
max_width[col] = max(max_width[col], len(str(val or "")))
|
||||
|
||||
if iface_val != next_iface or is_last:
|
||||
if row > group_start:
|
||||
ws.merge_cells(
|
||||
start_row=group_start, start_column=COLS["Interface"],
|
||||
end_row=row, end_column=COLS["Interface"]
|
||||
)
|
||||
for r in range(group_start, row + 1):
|
||||
c = ws.cell(r, COLS["Interface"])
|
||||
c.fill = iface_fill
|
||||
c.font = Font(bold=True, size=10)
|
||||
c.alignment = center
|
||||
c.border = thick_border
|
||||
group_start = row + 1
|
||||
|
||||
ws.row_dimensions[row].height = 18
|
||||
|
||||
for col, width in max_width.items():
|
||||
ws.column_dimensions[get_column_letter(col)].width = min(width + 4, 45)
|
||||
|
||||
|
||||
def export_to_excel(json_file_path: str, output_file_excel: str) -> str:
|
||||
with open(json_file_path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
|
||||
rows = _parse_interfaces(data)
|
||||
|
||||
export_rows = [{k: v for k, v in r.items() if k != "_is_sub"} for r in rows]
|
||||
|
||||
df = pd.DataFrame(export_rows, columns=[
|
||||
"Interface", "Type", "Description", "Enabled", "VLAN", "IP", "Préfixe", "VRF"
|
||||
])
|
||||
|
||||
with pd.ExcelWriter(output_file_excel, engine="openpyxl") as writer:
|
||||
df.to_excel(writer, sheet_name="Interfaces", index=False)
|
||||
|
||||
wb = load_workbook(output_file_excel)
|
||||
_style_interfaces(wb["Interfaces"])
|
||||
wb.save(output_file_excel)
|
||||
|
||||
print(f"✓ Export interfaces OK : {output_file_excel}")
|
||||
return output_file_excel
|
||||
@@ -8,6 +8,8 @@ from openpyxl import load_workbook
|
||||
from scripts.style_excel.style_address_groups import style_address_groups
|
||||
from scripts.style_excel.style_service_groups import style_service_groups
|
||||
from scripts.style_excel.style_matrice_flux import style_matrice_flux
|
||||
from scripts.style_excel.style_addresses import style_addresses
|
||||
from scripts.style_excel.style_services import style_services
|
||||
|
||||
def export_to_excel(json_file_path, output_file_excel):
|
||||
"""
|
||||
@@ -192,20 +194,46 @@ def export_to_excel(json_file_path, output_file_excel):
|
||||
for m in cfg.get("members", [])
|
||||
])
|
||||
|
||||
df_addresses = pd.DataFrame([
|
||||
{
|
||||
"Name": name,
|
||||
"IP / Masque": cfg.get("ip_netmask", "") if "/" in cfg.get("ip_netmask", "")
|
||||
else (cfg.get("ip_netmask", "") + "/32" if cfg.get("ip_netmask") else ""),
|
||||
"Description": cfg.get("description", ""),
|
||||
"Tags": cfg.get("misc", ""),
|
||||
}
|
||||
for name, cfg in sorted(addresses.items())
|
||||
])
|
||||
|
||||
df_services = pd.DataFrame([
|
||||
{
|
||||
"Name": name,
|
||||
"Protocol": cfg.get("protocol", ""),
|
||||
"Port": cfg.get("port", ""),
|
||||
"Description": cfg.get("description", ""),
|
||||
}
|
||||
for name, cfg in sorted(services.items())
|
||||
])
|
||||
|
||||
# === Export Excel ===
|
||||
firewall_type = data.get("firewall-device", {}).get("type", "firewall").replace(" ","_").lower()
|
||||
date = time.strftime("%Y%m%d")
|
||||
|
||||
with pd.ExcelWriter(output_file_excel, engine="openpyxl") as writer:
|
||||
df_addr.to_excel(writer,sheet_name="Address-Groups",index=False)
|
||||
df_srv.to_excel(writer,sheet_name="Service-Groups",index=False)
|
||||
df.to_excel(writer,sheet_name="Matrice Flux",index=False,startrow=1)
|
||||
df_addresses.to_excel(writer, sheet_name="Addresses", index=False)
|
||||
df_addr.to_excel(writer, sheet_name="Address-Groups", index=False)
|
||||
df_services.to_excel(writer, sheet_name="Services", index=False)
|
||||
df_srv.to_excel(writer, sheet_name="Service-Groups", index=False)
|
||||
df.to_excel(writer, sheet_name="Matrice Flux", index=False, startrow=1)
|
||||
|
||||
|
||||
wb = load_workbook(output_file_excel)
|
||||
if "Sheet1" in wb.sheetnames:
|
||||
del wb["Sheet1"]
|
||||
|
||||
style_addresses(wb["Addresses"])
|
||||
style_address_groups(wb["Address-Groups"], address_groups)
|
||||
style_services(wb["Services"])
|
||||
style_service_groups(wb["Service-Groups"], service_groups)
|
||||
style_matrice_flux(wb["Matrice Flux"])
|
||||
|
||||
|
||||
@@ -38,37 +38,46 @@ class ParserMixin:
|
||||
"name": interface.name,
|
||||
"config": {
|
||||
"name": interface.name,
|
||||
"type": "iana-if-type:ethernetCsmacd" if interface.interface_type == "ethernet" else "iana-if-type:ieee8023adLag",
|
||||
"type": interface.interface_type if interface.interface_type else None,
|
||||
"enabled": interface.enabled,
|
||||
"description": interface.comment or ""
|
||||
}
|
||||
}
|
||||
|
||||
if interface.ip:
|
||||
intf_config["subinterfaces"] = {
|
||||
"subinterface": [
|
||||
{
|
||||
subinterfaces = [
|
||||
{
|
||||
"index": interface.misc or 0,
|
||||
"config": {
|
||||
"index": interface.misc or 0,
|
||||
"config": {
|
||||
"index": interface.misc or 0,
|
||||
"enabled": interface.enabled
|
||||
},
|
||||
"oc-ip:ipv4": {
|
||||
"oc-ip:addresses": {
|
||||
"oc-ip:address": [
|
||||
{
|
||||
"enabled": interface.enabled
|
||||
},
|
||||
"oc-ip:ipv4": {
|
||||
"oc-ip:addresses": {
|
||||
"oc-ip:address": [
|
||||
{
|
||||
"oc-ip:ip": interface.ip,
|
||||
"oc-ip:config": {
|
||||
"oc-ip:ip": interface.ip,
|
||||
"oc-ip:config": {
|
||||
"oc-ip:ip": interface.ip,
|
||||
"oc-ip:prefix-length": interface.netmask if interface.netmask else 24
|
||||
}
|
||||
"oc-ip:prefix-length": interface.netmask if interface.netmask else 24
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
if interface.interface_type == "vlan":
|
||||
subinterfaces.append({
|
||||
"index": interface.vlan or None,
|
||||
"config": {
|
||||
"index": interface.vlan or None,
|
||||
}
|
||||
})
|
||||
|
||||
intf_config["subinterfaces"] = {"subinterface": subinterfaces}
|
||||
|
||||
|
||||
openconfig["openconfig-interfaces:interfaces"]["interface"].append(intf_config)
|
||||
|
||||
|
||||
@@ -46,13 +46,17 @@ class StormshieldParser(ParserMixin):
|
||||
current_section = line.strip("[]")
|
||||
continue
|
||||
|
||||
inline_comment = ""
|
||||
if "#" in line:
|
||||
inline_comment = line.split("#", 1)[1].strip()
|
||||
|
||||
if current_section in ("Host", "Network", "Fqdn"):
|
||||
match = re.match(r"([^=]+)=([^,#]+)", line)
|
||||
if match:
|
||||
name = match.group(1).strip()
|
||||
ip = match.group(2).strip()
|
||||
self.config["address_objects"].append(
|
||||
AddressObject(name=name, ip_netmask=ip)
|
||||
AddressObject(name=name, ip_netmask=ip, description=inline_comment)
|
||||
)
|
||||
|
||||
elif current_section == "Service":
|
||||
@@ -62,7 +66,7 @@ class StormshieldParser(ParserMixin):
|
||||
port = match.group(2)
|
||||
proto = match.group(3).lower()
|
||||
self.config["service_objects"].append(
|
||||
ServiceObject(name=name, protocol=proto, port=port)
|
||||
ServiceObject(name=name, protocol=proto, port=port, description=inline_comment)
|
||||
)
|
||||
|
||||
def _parse_address_groups(self):
|
||||
@@ -156,18 +160,7 @@ class StormshieldParser(ParserMixin):
|
||||
|
||||
def _add_interface(self, section_name, data):
|
||||
"""Crée un objet Interface à partir d’une section complète"""
|
||||
if section_name.lower().startswith("vlan"):
|
||||
iface_type = "vlan"
|
||||
elif section_name.lower().startswith("bridge"):
|
||||
iface_type = "bridge"
|
||||
elif section_name.lower().startswith("wifi"):
|
||||
iface_type = "wifi"
|
||||
elif section_name.lower().startswith("loopback"):
|
||||
iface_type = "loopback"
|
||||
elif section_name.lower().startswith("agg"):
|
||||
iface_type = "aggregate"
|
||||
else:
|
||||
iface_type = "ethernet"
|
||||
iface_type = section_name.rstrip("0123456789")
|
||||
|
||||
enabled = data.get("State", "0") == "1"
|
||||
name = data.get("Name", section_name)
|
||||
@@ -187,6 +180,7 @@ class StormshieldParser(ParserMixin):
|
||||
comment=comment,
|
||||
interface_type=iface_type,
|
||||
enabled=enabled,
|
||||
vlan=data.get("Tag") if data.get("Tag") and iface_type == "vlan" else None
|
||||
)
|
||||
|
||||
self.config["interfaces"].append(interface)
|
||||
|
||||
@@ -61,6 +61,7 @@ class Interface:
|
||||
comment: str = None
|
||||
interface_type: str = None
|
||||
enabled: bool = True
|
||||
vlan: str = None
|
||||
|
||||
@dataclass
|
||||
class SecurityRule:
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
|
||||
from openpyxl.utils import get_column_letter
|
||||
|
||||
center = Alignment(horizontal="center", vertical="center")
|
||||
left = Alignment(horizontal="left", vertical="center")
|
||||
|
||||
red_fill = PatternFill(start_color="FF9999", fill_type="solid")
|
||||
yellow_fill = PatternFill(start_color="FFFF99", fill_type="solid")
|
||||
|
||||
thick_border = Border(*(Side(style="thick"),)*4)
|
||||
thin_border = Border(*(Side(style="thin"),)*4)
|
||||
|
||||
def style_addresses(ws):
|
||||
|
||||
col_name, col_ip, col_desc, col_tags = 1, 2, 3, 4
|
||||
|
||||
max_width = {1: 0, 2: 0, 3: 0, 4: 0}
|
||||
|
||||
for row in range(2, ws.max_row + 1):
|
||||
name = ws.cell(row=row, column=col_name).value
|
||||
ip = ws.cell(row=row, column=col_ip).value
|
||||
desc = ws.cell(row=row, column=col_desc).value
|
||||
tags = ws.cell(row=row, column=col_tags).value
|
||||
|
||||
ws.cell(row=row, column=col_name).fill = red_fill
|
||||
ws.cell(row=row, column=col_name).font = Font(bold=True)
|
||||
ws.cell(row=row, column=col_name).alignment = left
|
||||
ws.cell(row=row, column=col_name).border = thin_border
|
||||
|
||||
for col in (col_ip, col_desc, col_tags):
|
||||
ws.cell(row=row, column=col).alignment = left
|
||||
ws.cell(row=row, column=col).border = thick_border
|
||||
ws.cell(row=row, column=col).fill = yellow_fill
|
||||
|
||||
max_width[1] = max(max_width[1], len(str(name or "")))
|
||||
max_width[2] = max(max_width[2], len(str(ip or "")))
|
||||
max_width[3] = max(max_width[3], len(str(desc or "")))
|
||||
max_width[4] = max(max_width[4], len(str(tags or "")))
|
||||
|
||||
for col in max_width:
|
||||
ws.column_dimensions[get_column_letter(col)].width = max_width[col] + 2
|
||||
|
||||
for row in range(2, ws.max_row + 1):
|
||||
ws.row_dimensions[row].height = 18
|
||||
@@ -0,0 +1,51 @@
|
||||
from openpyxl.styles import PatternFill, Border, Side, Alignment, Font
|
||||
from openpyxl.utils import get_column_letter
|
||||
|
||||
center = Alignment(horizontal="center", vertical="center")
|
||||
left = Alignment(horizontal="left", vertical="center")
|
||||
|
||||
red_fill = PatternFill(start_color="FF9999", fill_type="solid")
|
||||
yellow_fill = PatternFill(start_color="FFFF99", fill_type="solid")
|
||||
|
||||
thick_border = Border(*(Side(style="thick"),)*4)
|
||||
thin_border = Border(*(Side(style="thin"),)*4)
|
||||
|
||||
def style_services(ws):
|
||||
|
||||
col_name, col_proto, col_port, col_desc = 1, 2, 3, 4
|
||||
|
||||
max_width = {1: 0, 2: 0, 3: 0, 4: 0}
|
||||
|
||||
for row in range(2, ws.max_row + 1):
|
||||
name = ws.cell(row=row, column=col_name).value
|
||||
proto = ws.cell(row=row, column=col_proto).value
|
||||
port = ws.cell(row=row, column=col_port).value
|
||||
desc = ws.cell(row=row, column=col_desc).value
|
||||
|
||||
ws.cell(row=row, column=col_name).fill = red_fill
|
||||
ws.cell(row=row, column=col_name).font = Font(bold=True)
|
||||
ws.cell(row=row, column=col_name).alignment = left
|
||||
ws.cell(row=row, column=col_name).border = thin_border
|
||||
|
||||
ws.cell(row=row, column=col_proto).alignment = center
|
||||
ws.cell(row=row, column=col_proto).border = thick_border
|
||||
ws.cell(row=row, column=col_proto).fill = yellow_fill
|
||||
|
||||
ws.cell(row=row, column=col_port).alignment = center
|
||||
ws.cell(row=row, column=col_port).border = thick_border
|
||||
ws.cell(row=row, column=col_port).fill = yellow_fill
|
||||
|
||||
ws.cell(row=row, column=col_desc).alignment = left
|
||||
ws.cell(row=row, column=col_desc).border = thick_border
|
||||
ws.cell(row=row, column=col_desc).fill = yellow_fill
|
||||
|
||||
max_width[1] = max(max_width[1], len(str(name or "")))
|
||||
max_width[2] = max(max_width[2], len(str(proto or "")))
|
||||
max_width[3] = max(max_width[3], len(str(port or "")))
|
||||
max_width[4] = max(max_width[4], len(str(desc or "")))
|
||||
|
||||
for col in max_width:
|
||||
ws.column_dimensions[get_column_letter(col)].width = max_width[col] + 2
|
||||
|
||||
for row in range(2, ws.max_row + 1):
|
||||
ws.row_dimensions[row].height = 18
|
||||
@@ -15,6 +15,7 @@ Données extraites : Fichiers et dossiers de configurations d'origine.
|
||||
Rapports générés :
|
||||
- Matrice de flux (Excel) pour visualiser les communications et les règles de trafic.
|
||||
- Matrice de routage (Excel) pour cartographier les routes statiques.
|
||||
- Détail des interfaces (Excel) pour visualiser la configuration des interfaces.
|
||||
```
|
||||
|
||||
- Module Switch
|
||||
|
||||
@@ -75,11 +75,12 @@ class ToolTip:
|
||||
def open_firewall_gui_multi(app, OUTPUT_DIR, HELP_FILE_FW, FIREWALL_DIR, FIREWALL_MAIN):
|
||||
app2 = tk.Toplevel(app)
|
||||
app2.title("Analyse Configuration Firewall - Plusieurs firewall")
|
||||
app2.geometry("800x450")
|
||||
app2.geometry("800x500")
|
||||
app2.resizable(True, True)
|
||||
|
||||
matrice_flux = tk.BooleanVar()
|
||||
matrice_routage = tk.BooleanVar()
|
||||
interfaces = tk.BooleanVar()
|
||||
|
||||
content = make_scrollable(app2)
|
||||
|
||||
@@ -158,6 +159,8 @@ def open_firewall_gui_multi(app, OUTPUT_DIR, HELP_FILE_FW, FIREWALL_DIR, FIREWAL
|
||||
cmd.append("-f")
|
||||
if matrice_routage.get():
|
||||
cmd.append("-r")
|
||||
if interfaces.get():
|
||||
cmd.append("-i")
|
||||
|
||||
cmd.append("-o")
|
||||
if item["type"] == "file":
|
||||
@@ -376,9 +379,16 @@ def open_firewall_gui_multi(app, OUTPUT_DIR, HELP_FILE_FW, FIREWALL_DIR, FIREWAL
|
||||
content,
|
||||
text="Générer la matrice de routage en Excel (route statique uniquement)",
|
||||
variable=matrice_routage
|
||||
).pack(anchor="w", padx=10, pady=(0, 10))
|
||||
).pack(anchor="w", padx=10, pady=(0, 0))
|
||||
matrice_routage.set(True)
|
||||
|
||||
ttk.Checkbutton(
|
||||
content,
|
||||
text="Générer la configuration des interfaces en Excel",
|
||||
variable=interfaces
|
||||
).pack(anchor="w", padx=10, pady=(0, 10))
|
||||
interfaces.set(True)
|
||||
|
||||
ttk.Label(
|
||||
content,
|
||||
text="Dossier de sortie :",
|
||||
@@ -418,7 +428,7 @@ def open_firewall_gui(root, BASE_DIR):
|
||||
|
||||
app = tk.Toplevel(root)
|
||||
app.title("Analyse Configuration Firewall")
|
||||
app.geometry("800x450")
|
||||
app.geometry("800x500")
|
||||
app.resizable(True, True)
|
||||
|
||||
firewall_var = tk.StringVar()
|
||||
@@ -427,6 +437,7 @@ def open_firewall_gui(root, BASE_DIR):
|
||||
|
||||
matrice_flux = tk.BooleanVar()
|
||||
matrice_routage = tk.BooleanVar()
|
||||
interfaces = tk.BooleanVar()
|
||||
|
||||
def browse_input():
|
||||
fw_type = firewall_var.get()
|
||||
@@ -453,22 +464,15 @@ def open_firewall_gui(root, BASE_DIR):
|
||||
f_json = os.path.join(OUTPUT_DIR, f"{fw}_{output_var.get()}.json")
|
||||
f_flux = os.path.join(OUTPUT_DIR, f"matrice_flux_{fw}_{output_var.get()}.xlsx")
|
||||
f_routage = os.path.join(OUTPUT_DIR, f"matrice_routage_{fw}_{output_var.get()}.xlsx")
|
||||
f_interfaces = os.path.join(OUTPUT_DIR, f"interfaces_{fw}_{output_var.get()}.xlsx")
|
||||
else:
|
||||
dt = datetime.now().strftime("%Y%m%d")
|
||||
f_json = os.path.join(OUTPUT_DIR, f"{fw}_{dt}.json")
|
||||
f_flux = os.path.join(OUTPUT_DIR, f"matrice_flux_{fw}_{dt}.xlsx")
|
||||
f_routage = os.path.join(OUTPUT_DIR, f"matrice_routage_{fw}_{dt}.xlsx")
|
||||
f_interfaces = os.path.join(OUTPUT_DIR, f"interfaces_{fw}_{dt}.xlsx")
|
||||
|
||||
if not matrice_flux.get():
|
||||
if not matrice_routage.get():
|
||||
output_label_var.set("Fichier de sortie :\n" + f_json)
|
||||
else:
|
||||
output_label_var.set("Fichiers de sortie :\n" + f_json + "\n" + f_routage)
|
||||
else:
|
||||
if not matrice_routage.get():
|
||||
output_label_var.set("Fichiers de sortie :\n" + f_json + "\n" + f_flux)
|
||||
else:
|
||||
output_label_var.set("Fichiers de sortie :\n" + f_json + "\n" + f_flux + "\n" + f_routage)
|
||||
output_label_var.set("Fichier de sortie :\n" + f_json + ("\n" + f_flux if matrice_flux.get() else "") + ("\n" + f_routage if matrice_routage.get() else "") + ("\n" + f_interfaces if interfaces.get() else ""))
|
||||
app.update_idletasks()
|
||||
|
||||
def open_output_folder():
|
||||
@@ -518,9 +522,10 @@ def open_firewall_gui(root, BASE_DIR):
|
||||
|
||||
if matrice_flux.get():
|
||||
cmd.append("-f")
|
||||
|
||||
if matrice_routage.get():
|
||||
cmd.append("-r")
|
||||
if interfaces.get():
|
||||
cmd.append("-i")
|
||||
|
||||
print("Commande exécutée :", " ".join(cmd))
|
||||
print("Dossier courant (cwd) :", FIREWALL_DIR)
|
||||
@@ -636,15 +641,23 @@ def open_firewall_gui(root, BASE_DIR):
|
||||
app,
|
||||
text="Générer la matrice de routage en Excel (route statique uniquement)",
|
||||
variable=matrice_routage
|
||||
).pack(anchor="w", padx=10, pady=(0, 10))
|
||||
).pack(anchor="w", padx=10, pady=(0, 0))
|
||||
matrice_routage.set(True)
|
||||
|
||||
ttk.Checkbutton(
|
||||
app,
|
||||
text="Générer la configuration des interfaces en Excel",
|
||||
variable=interfaces
|
||||
).pack(anchor="w", padx=10, pady=(0, 10))
|
||||
interfaces.set(True)
|
||||
|
||||
output_label_var = tk.StringVar()
|
||||
ttk.Label(app, textvariable=output_label_var).pack(anchor="w", padx=10)
|
||||
firewall_var.trace_add("write", update_output_label)
|
||||
output_var.trace_add("write", update_output_label)
|
||||
matrice_flux.trace_add("write", update_output_label)
|
||||
matrice_routage.trace_add("write", update_output_label)
|
||||
interfaces.trace_add("write", update_output_label)
|
||||
update_output_label()
|
||||
|
||||
ttk.Button(
|
||||
|
||||
@@ -6,6 +6,7 @@ Cet outil permet de **récupérer les données des configurations de différents
|
||||
|
||||
- Il fournit également la possibilité de générer une **matrice de flux au format Excel** pour visualiser les communications et règles de trafic dans l’infrastructure.
|
||||
- Il founit également la possibilité de générer une **matrice de routage au format Excel** pour visualiser les routes statiques dans l’infrastructure.
|
||||
- Il founit également la possibilité de générer le **détail des interfaces au format Excel** pour visualiser la configuration des interfaces.
|
||||
|
||||
## Utilisation
|
||||
|
||||
|
||||
26
main.py
26
main.py
@@ -58,9 +58,10 @@ def bootstrap_venv():
|
||||
|
||||
def relaunch_in_venv():
|
||||
print("[INFO] Relance du script dans le venv…")
|
||||
script_path = os.path.abspath(__file__)
|
||||
subprocess.check_call([
|
||||
venv_python(),
|
||||
__file__
|
||||
script_path
|
||||
])
|
||||
sys.exit(0)
|
||||
|
||||
@@ -68,14 +69,30 @@ def relaunch_in_venv():
|
||||
def open_main_gui():
|
||||
root = tk.Tk()
|
||||
root.title("Analyse Réseau")
|
||||
root.geometry("650x350")
|
||||
root.geometry("650x500")
|
||||
root.resizable(True, True)
|
||||
|
||||
header_frame = tk.Frame(root)
|
||||
header_frame.pack(fill="x", pady=10, padx=10)
|
||||
|
||||
logo_path = os.path.join(BASE_DIR, "Computacenter_logo.png")
|
||||
if os.path.isfile(logo_path):
|
||||
try:
|
||||
logo_img = tk.PhotoImage(file=logo_path)
|
||||
|
||||
logo_img = logo_img.subsample(15, 15)
|
||||
|
||||
logo_label = tk.Label(header_frame, image=logo_img)
|
||||
logo_label.image = logo_img
|
||||
logo_label.pack(side="right")
|
||||
except Exception as e:
|
||||
print(f"[WARN] Impossible de charger le logo : {e}")
|
||||
|
||||
ttk.Label(
|
||||
root,
|
||||
text="Analyse Réseau",
|
||||
font=("Arial", 16, "bold")
|
||||
).pack(pady=20)
|
||||
).pack(pady=(0, 20))
|
||||
|
||||
ttk.Label(
|
||||
root,
|
||||
@@ -94,7 +111,8 @@ def open_main_gui():
|
||||
root,
|
||||
text="(Convertir les données au format normalisé Yang dans un fichier JSON)" \
|
||||
"\n + possibilité de générer une matrice de flux en Excel" \
|
||||
"\n + possibilité de générer une matrice de routage en Excel (route statique uniquement)",
|
||||
"\n + possibilité de générer une matrice de routage en Excel (route statique uniquement)" \
|
||||
"\n + possibilité de générer un rapport des interfaces en Excel",
|
||||
font=("Arial", 9, "italic"),
|
||||
anchor="center",
|
||||
justify="center"
|
||||
|
||||
Reference in New Issue
Block a user