feat: review detected networks in one import plan
Show a combined network and VRF dialog only when selected VMs introduce missing prefixes. Allow a different existing or newly named VRF per network and cache existing prefixes to prevent repeated prompts.
This commit is contained in:
@@ -9,9 +9,9 @@ Windows-Desktopanwendung zum Importieren und Synchronisieren virtueller Maschine
|
|||||||
- Mit Windows DPAPI verschlüsselte Passwörter, API-Token und Token-Secrets
|
- Mit Windows DPAPI verschlüsselte Passwörter, API-Token und Token-Secrets
|
||||||
- Automatische Übernahme des Cluster-Mandanten mit verbindlicher Bestätigung vor dem Sync
|
- Automatische Übernahme des Cluster-Mandanten mit verbindlicher Bestätigung vor dem Sync
|
||||||
- Mandantenzuweisung für IPv4-/IPv6-Adressen und erkannte NetBox-Präfixe
|
- Mandantenzuweisung für IPv4-/IPv6-Adressen und erkannte NetBox-Präfixe
|
||||||
- Bestätigungsdialog mit Subnetzgrößen- und vorausgefüllter VRF-Auswahl sowie optionaler VRF-Erstellung
|
- Gemeinsame Importmaske für alle neu erkannten Netze mit Subnetzgröße und vorausgefüllter VRF-Auswahl
|
||||||
|
- Mehrere neue VRFs direkt in der Netzwerkmaske anlegen; Namensfelder erscheinen nur bei Bedarf
|
||||||
- Auswahl vorhandener Mandanten-VRFs oder automatische VRF-Erstellung pro Cluster mit frei wählbarem Namen
|
- Auswahl vorhandener Mandanten-VRFs oder automatische VRF-Erstellung pro Cluster mit frei wählbarem Namen
|
||||||
- Eigenes Fenster zur Stapelanlage mehrerer VRFs und Netzwerke pro Mandant
|
|
||||||
- Wiederverwendung bereits vorhandener, zur IP passender Präfixe bei erneuten Imports
|
- Wiederverwendung bereits vorhandener, zur IP passender Präfixe bei erneuten Imports
|
||||||
- Optionale Unterstützung selbstsignierter TLS-Zertifikate
|
- Optionale Unterstützung selbstsignierter TLS-Zertifikate
|
||||||
- Synchronisierung von VMs, Hardwaredaten, Interfaces und IP-Adressen
|
- Synchronisierung von VMs, Hardwaredaten, Interfaces und IP-Adressen
|
||||||
|
|||||||
@@ -213,9 +213,13 @@ class VRFSelectionDialog(tk.Toplevel):
|
|||||||
wraplength=490,
|
wraplength=490,
|
||||||
justify="left",
|
justify="left",
|
||||||
).pack(anchor="w", pady=(8, 14))
|
).pack(anchor="w", pady=(8, 14))
|
||||||
ttk.Combobox(body, textvariable=self.selection, values=values, state="readonly").pack(fill="x")
|
selection_combo = ttk.Combobox(body, textvariable=self.selection, values=values, state="readonly")
|
||||||
ttk.Label(body, text="Name bei automatischer Erstellung").pack(anchor="w", pady=(14, 4))
|
selection_combo.pack(fill="x")
|
||||||
ttk.Entry(body, textvariable=self.new_vrf_name).pack(fill="x")
|
selection_combo.bind("<<ComboboxSelected>>", self.update_name_field)
|
||||||
|
self.name_frame = ttk.Frame(body)
|
||||||
|
ttk.Label(self.name_frame, text="Name der neuen VRF").pack(anchor="w", pady=(14, 4))
|
||||||
|
ttk.Entry(self.name_frame, textvariable=self.new_vrf_name).pack(fill="x")
|
||||||
|
self.update_name_field()
|
||||||
|
|
||||||
buttons = ttk.Frame(body)
|
buttons = ttk.Frame(body)
|
||||||
buttons.pack(anchor="e", pady=(22, 0))
|
buttons.pack(anchor="e", pady=(22, 0))
|
||||||
@@ -224,6 +228,12 @@ class VRFSelectionDialog(tk.Toplevel):
|
|||||||
self.protocol("WM_DELETE_WINDOW", self.destroy)
|
self.protocol("WM_DELETE_WINDOW", self.destroy)
|
||||||
self.wait_window(self)
|
self.wait_window(self)
|
||||||
|
|
||||||
|
def update_name_field(self, _event=None):
|
||||||
|
if self.selection.get() == self.AUTO_CREATE:
|
||||||
|
self.name_frame.pack(fill="x")
|
||||||
|
else:
|
||||||
|
self.name_frame.pack_forget()
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
selected = self.selection.get()
|
selected = self.selection.get()
|
||||||
if selected == self.AUTO_CREATE:
|
if selected == self.AUTO_CREATE:
|
||||||
@@ -394,6 +404,180 @@ class PrefixCreationDialog(tk.Toplevel):
|
|||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
|
|
||||||
|
class DetectedNetworksDialog(tk.Toplevel):
|
||||||
|
"""Review all newly detected networks and their VRFs in one import plan."""
|
||||||
|
|
||||||
|
AUTO_CREATE = "➕ Neue VRF anlegen"
|
||||||
|
|
||||||
|
def __init__(self, parent, networks, vrfs, default_vrf_id, tenant_name):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.title("Neue Netzwerke prüfen")
|
||||||
|
self.geometry("1060x620")
|
||||||
|
self.minsize(900, 480)
|
||||||
|
self.transient(parent)
|
||||||
|
self.grab_set()
|
||||||
|
self.result = None
|
||||||
|
self.rows = []
|
||||||
|
self.vrf_map = {}
|
||||||
|
|
||||||
|
vrf_values = []
|
||||||
|
for vrf in vrfs:
|
||||||
|
rd = getattr(vrf, "rd", None)
|
||||||
|
display = f"{vrf.name} (RD: {rd})" if rd else vrf.name
|
||||||
|
self.vrf_map[display] = vrf.id
|
||||||
|
vrf_values.append(display)
|
||||||
|
vrf_values.append(self.AUTO_CREATE)
|
||||||
|
default_vrf = next(
|
||||||
|
(display for display, vrf_id in self.vrf_map.items() if vrf_id == default_vrf_id),
|
||||||
|
vrf_values[0],
|
||||||
|
)
|
||||||
|
|
||||||
|
body = ttk.Frame(self, padding=20)
|
||||||
|
body.pack(fill="both", expand=True)
|
||||||
|
ttk.Label(body, text="Neue Netzwerke erkannt", font=("Segoe UI Semibold", 16)).pack(anchor="w")
|
||||||
|
ttk.Label(
|
||||||
|
body,
|
||||||
|
text=(
|
||||||
|
"Nur noch nicht vorhandene Netze werden angezeigt. Subnetzgröße und VRF können pro Netz geändert "
|
||||||
|
"werden. Bei ‚Neue VRF anlegen‘ erscheint ein Namensfeld in derselben Zeile."
|
||||||
|
),
|
||||||
|
wraplength=980,
|
||||||
|
foreground="#52606d",
|
||||||
|
).pack(anchor="w", pady=(5, 14))
|
||||||
|
|
||||||
|
header = ttk.Frame(body)
|
||||||
|
header.pack(fill="x", padx=(2, 20))
|
||||||
|
ttk.Label(header, text="Anlegen", width=8).grid(row=0, column=0, sticky="w")
|
||||||
|
ttk.Label(header, text="Erkannte IP", width=21).grid(row=0, column=1, sticky="w")
|
||||||
|
ttk.Label(header, text="Größe", width=9).grid(row=0, column=2, sticky="w")
|
||||||
|
ttk.Label(header, text="Netzwerk", width=25).grid(row=0, column=3, sticky="w")
|
||||||
|
ttk.Label(header, text="VRF", width=34).grid(row=0, column=4, sticky="w")
|
||||||
|
|
||||||
|
container = ttk.Frame(body)
|
||||||
|
container.pack(fill="both", expand=True, pady=(4, 10))
|
||||||
|
canvas = tk.Canvas(container, borderwidth=0, highlightthickness=0)
|
||||||
|
scrollbar = ttk.Scrollbar(container, orient="vertical", command=canvas.yview)
|
||||||
|
self.rows_frame = ttk.Frame(canvas)
|
||||||
|
self.rows_frame.bind(
|
||||||
|
"<Configure>",
|
||||||
|
lambda _event: canvas.configure(scrollregion=canvas.bbox("all")),
|
||||||
|
)
|
||||||
|
window_id = canvas.create_window((0, 0), window=self.rows_frame, anchor="nw")
|
||||||
|
canvas.bind("<Configure>", lambda event: canvas.itemconfigure(window_id, width=event.width))
|
||||||
|
canvas.configure(yscrollcommand=scrollbar.set)
|
||||||
|
canvas.pack(side="left", fill="both", expand=True)
|
||||||
|
scrollbar.pack(side="right", fill="y")
|
||||||
|
|
||||||
|
for index, item in enumerate(networks):
|
||||||
|
self.add_network_row(index, item, vrf_values, default_vrf, tenant_name)
|
||||||
|
|
||||||
|
buttons = ttk.Frame(body)
|
||||||
|
buttons.pack(fill="x")
|
||||||
|
ttk.Button(buttons, text="Import abbrechen", command=self.destroy).pack(side="left")
|
||||||
|
ttk.Button(buttons, text="Ohne neue Netze fortfahren", command=self.skip_all).pack(side="right", padx=(8, 0))
|
||||||
|
ttk.Button(buttons, text="Auswahl übernehmen", command=self.accept, style="Primary.TButton").pack(side="right")
|
||||||
|
self.protocol("WM_DELETE_WINDOW", self.destroy)
|
||||||
|
self.wait_window(self)
|
||||||
|
|
||||||
|
def add_network_row(self, index, item, vrf_values, default_vrf, tenant_name):
|
||||||
|
row_frame = ttk.Frame(self.rows_frame, padding=(4, 7))
|
||||||
|
row_frame.pack(fill="x")
|
||||||
|
enabled = tk.BooleanVar(value=True)
|
||||||
|
prefix_length = tk.StringVar(value=f"/{item['suggested_prefixlen']}")
|
||||||
|
network_text = tk.StringVar()
|
||||||
|
vrf_selection = tk.StringVar(value=default_vrf)
|
||||||
|
new_vrf_name = tk.StringVar(value=f"{tenant_name} - {item['suggested_network'].network_address}")
|
||||||
|
|
||||||
|
ttk.Checkbutton(row_frame, variable=enabled).grid(row=0, column=0, sticky="w", padx=(0, 12))
|
||||||
|
ttk.Label(row_frame, text=str(item["host_address"]), width=21).grid(row=0, column=1, sticky="w")
|
||||||
|
choices = self.prefix_choices(item["host_address"], item["detected_prefixlen"])
|
||||||
|
size_combo = ttk.Combobox(row_frame, textvariable=prefix_length, values=choices, state="readonly", width=7)
|
||||||
|
size_combo.grid(row=0, column=2, sticky="w", padx=(0, 12))
|
||||||
|
ttk.Label(row_frame, textvariable=network_text, width=25).grid(row=0, column=3, sticky="w")
|
||||||
|
vrf_combo = ttk.Combobox(
|
||||||
|
row_frame,
|
||||||
|
textvariable=vrf_selection,
|
||||||
|
values=vrf_values,
|
||||||
|
state="readonly",
|
||||||
|
width=34,
|
||||||
|
)
|
||||||
|
vrf_combo.grid(row=0, column=4, sticky="ew")
|
||||||
|
row_frame.columnconfigure(4, weight=1)
|
||||||
|
|
||||||
|
name_frame = ttk.Frame(row_frame)
|
||||||
|
ttk.Label(name_frame, text="Name der neuen VRF:").pack(side="left")
|
||||||
|
ttk.Entry(name_frame, textvariable=new_vrf_name).pack(side="left", fill="x", expand=True, padx=(8, 0))
|
||||||
|
|
||||||
|
row = {
|
||||||
|
"frame": row_frame,
|
||||||
|
"enabled": enabled,
|
||||||
|
"host_address": item["host_address"],
|
||||||
|
"prefix_length": prefix_length,
|
||||||
|
"network_text": network_text,
|
||||||
|
"vrf_selection": vrf_selection,
|
||||||
|
"new_vrf_name": new_vrf_name,
|
||||||
|
"name_frame": name_frame,
|
||||||
|
}
|
||||||
|
self.rows.append(row)
|
||||||
|
|
||||||
|
size_combo.bind("<<ComboboxSelected>>", lambda _event, current=row: self.update_row(current))
|
||||||
|
vrf_combo.bind("<<ComboboxSelected>>", lambda _event, current=row: self.update_row(current))
|
||||||
|
self.update_row(row)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def prefix_choices(host_address, detected_prefixlen):
|
||||||
|
host = ipaddress.ip_address(host_address)
|
||||||
|
if host.version == 4:
|
||||||
|
return [f"/{length}" for length in range(8, 25)]
|
||||||
|
common = {32, 40, 48, 52, 56, 60, 64, 80, 96, 112, 120, 124, 126, 127, 128, detected_prefixlen}
|
||||||
|
return [f"/{length}" for length in sorted(common)]
|
||||||
|
|
||||||
|
def update_row(self, row):
|
||||||
|
length = int(row["prefix_length"].get().lstrip("/"))
|
||||||
|
network = ipaddress.ip_network(f"{row['host_address']}/{length}", strict=False)
|
||||||
|
row["network_text"].set(str(network))
|
||||||
|
if row["vrf_selection"].get() == self.AUTO_CREATE:
|
||||||
|
row["name_frame"].grid(row=1, column=4, sticky="ew", pady=(7, 0))
|
||||||
|
else:
|
||||||
|
row["name_frame"].grid_remove()
|
||||||
|
|
||||||
|
def skip_all(self):
|
||||||
|
self.result = []
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
decisions = {}
|
||||||
|
for row in self.rows:
|
||||||
|
if not row["enabled"].get():
|
||||||
|
continue
|
||||||
|
network = row["network_text"].get()
|
||||||
|
selected_vrf = row["vrf_selection"].get()
|
||||||
|
if selected_vrf == self.AUTO_CREATE:
|
||||||
|
vrf_name = row["new_vrf_name"].get().strip()
|
||||||
|
if not vrf_name:
|
||||||
|
messagebox.showwarning("VRF-Name fehlt", f"Bitte für {network} einen VRF-Namen eingeben.", parent=self)
|
||||||
|
return
|
||||||
|
decision = {"network": network, "vrf_id": None, "create_vrf": True, "vrf_name": vrf_name}
|
||||||
|
else:
|
||||||
|
decision = {
|
||||||
|
"network": network,
|
||||||
|
"vrf_id": self.vrf_map[selected_vrf],
|
||||||
|
"create_vrf": False,
|
||||||
|
"vrf_name": None,
|
||||||
|
}
|
||||||
|
existing = decisions.get(network)
|
||||||
|
if existing and existing != decision:
|
||||||
|
messagebox.showwarning(
|
||||||
|
"Netzwerk doppelt",
|
||||||
|
f"{network} wurde mit unterschiedlichen VRFs ausgewählt.",
|
||||||
|
parent=self,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
decisions[network] = decision
|
||||||
|
self.result = list(decisions.values())
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
|
||||||
class NetworkManagementDialog(tk.Toplevel):
|
class NetworkManagementDialog(tk.Toplevel):
|
||||||
"""Create multiple tenant VRFs and prefixes in one dedicated window."""
|
"""Create multiple tenant VRFs and prefixes in one dedicated window."""
|
||||||
|
|
||||||
@@ -663,7 +847,6 @@ class NetBoxVMImporter:
|
|||||||
buttons = ttk.Frame(main)
|
buttons = ttk.Frame(main)
|
||||||
buttons.grid(row=5, column=0, sticky="ew", pady=10)
|
buttons.grid(row=5, column=0, sticky="ew", pady=10)
|
||||||
ttk.Button(buttons, text="Alle auswählen", command=self.select_all).pack(side="left")
|
ttk.Button(buttons, text="Alle auswählen", command=self.select_all).pack(side="left")
|
||||||
ttk.Button(buttons, text="VRFs & Netzwerke", command=self.open_network_manager).pack(side="left", padx=8)
|
|
||||||
ttk.Button(buttons, text="Import / Sync starten", command=self.import_vms, style="Primary.TButton").pack(side="right")
|
ttk.Button(buttons, text="Import / Sync starten", command=self.import_vms, style="Primary.TButton").pack(side="right")
|
||||||
|
|
||||||
log_card = ttk.LabelFrame(main, text="Aktivitätsprotokoll", style="Card.TLabelframe")
|
log_card = ttk.LabelFrame(main, text="Aktivitätsprotokoll", style="Card.TLabelframe")
|
||||||
@@ -1232,7 +1415,11 @@ class NetBoxVMImporter:
|
|||||||
self.log("Synchronisierung ohne VRF-Auswahl abgebrochen")
|
self.log("Synchronisierung ohne VRF-Auswahl abgebrochen")
|
||||||
return
|
return
|
||||||
self.synced_prefixes = set()
|
self.synced_prefixes = set()
|
||||||
self.prefix_decisions = {}
|
prefix_plans = self.prepare_network_import(selected, tenant_name, tenant_id, vrf_id)
|
||||||
|
if prefix_plans is None:
|
||||||
|
self.log("Synchronisierung in der Netzwerkprüfung abgebrochen")
|
||||||
|
return
|
||||||
|
self.prefix_plans = prefix_plans
|
||||||
failures = []
|
failures = []
|
||||||
for item_id in selected:
|
for item_id in selected:
|
||||||
vm_data = self.vms[int(item_id)]
|
vm_data = self.vms[int(item_id)]
|
||||||
@@ -1279,6 +1466,81 @@ class NetBoxVMImporter:
|
|||||||
key=lambda item: item.name.casefold(),
|
key=lambda item: item.name.casefold(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def prepare_network_import(self, selected_items, tenant_name, tenant_id, default_vrf_id):
|
||||||
|
detected = {}
|
||||||
|
for item_id in selected_items:
|
||||||
|
vm_data = self.vms[int(item_id)]
|
||||||
|
for interface in vm_data.get("interfaces", []):
|
||||||
|
for ip_value in dict.fromkeys(interface.get("ips", [])):
|
||||||
|
address = self.ip_with_prefix(ip_value)
|
||||||
|
if not address:
|
||||||
|
continue
|
||||||
|
parsed = ipaddress.ip_interface(address)
|
||||||
|
if parsed.version == 4:
|
||||||
|
suggested_prefixlen = 24
|
||||||
|
else:
|
||||||
|
suggested_prefixlen = parsed.network.prefixlen
|
||||||
|
suggested_network = ipaddress.ip_network(
|
||||||
|
f"{parsed.ip}/{suggested_prefixlen}",
|
||||||
|
strict=False,
|
||||||
|
)
|
||||||
|
key = str(suggested_network)
|
||||||
|
detected.setdefault(
|
||||||
|
key,
|
||||||
|
{
|
||||||
|
"host_address": parsed.ip,
|
||||||
|
"host_addresses": set(),
|
||||||
|
"detected_prefixlen": parsed.network.prefixlen,
|
||||||
|
"suggested_prefixlen": suggested_prefixlen,
|
||||||
|
"suggested_network": suggested_network,
|
||||||
|
},
|
||||||
|
)["host_addresses"].add(parsed.ip)
|
||||||
|
|
||||||
|
tenant_vrf_ids = {vrf.id for vrf in self.tenant_vrfs(tenant_id)}
|
||||||
|
self.preexisting_prefixes = []
|
||||||
|
missing = []
|
||||||
|
for item in detected.values():
|
||||||
|
group_is_missing = False
|
||||||
|
for host in item["host_addresses"]:
|
||||||
|
covering = self.find_covering_prefixes(host, tenant_vrf_ids)
|
||||||
|
default_matches = [match for match in covering if match[3] == default_vrf_id]
|
||||||
|
matching_vrfs = {match[3] for match in covering}
|
||||||
|
reusable = None
|
||||||
|
if default_matches:
|
||||||
|
reusable = max(default_matches, key=lambda match: match[0])
|
||||||
|
elif len(matching_vrfs) == 1:
|
||||||
|
reusable = max(covering, key=lambda match: match[0])
|
||||||
|
if reusable:
|
||||||
|
_, prefix, existing_network, existing_vrf_id = reusable
|
||||||
|
cached = (prefix, existing_network, existing_vrf_id)
|
||||||
|
if cached not in self.preexisting_prefixes:
|
||||||
|
self.preexisting_prefixes.append(cached)
|
||||||
|
else:
|
||||||
|
group_is_missing = True
|
||||||
|
if group_is_missing:
|
||||||
|
missing.append(item)
|
||||||
|
|
||||||
|
if not missing:
|
||||||
|
self.log("Keine neuen Netzwerke erkannt")
|
||||||
|
return []
|
||||||
|
|
||||||
|
dialog = DetectedNetworksDialog(
|
||||||
|
self.root,
|
||||||
|
missing,
|
||||||
|
self.tenant_vrfs(tenant_id),
|
||||||
|
default_vrf_id,
|
||||||
|
tenant_name,
|
||||||
|
)
|
||||||
|
if dialog.result is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
for decision in dialog.result:
|
||||||
|
if decision.get("create_vrf"):
|
||||||
|
decision["vrf_id"] = self.get_or_create_tenant_vrf(decision["vrf_name"], tenant_id)
|
||||||
|
decision["create_vrf"] = False
|
||||||
|
self.log(f"Netzwerkplan bestätigt: {len(dialog.result)} neue(s) Netzwerk(e)")
|
||||||
|
return dialog.result
|
||||||
|
|
||||||
def open_network_manager(self):
|
def open_network_manager(self):
|
||||||
if self.nb is None or not self.tenant_map:
|
if self.nb is None or not self.tenant_map:
|
||||||
messagebox.showwarning(
|
messagebox.showwarning(
|
||||||
@@ -1468,16 +1730,23 @@ class NetBoxVMImporter:
|
|||||||
return matches
|
return matches
|
||||||
|
|
||||||
def sync_prefix_tenant(self, address, tenant_id, prefix_is_detected, default_vrf_id):
|
def sync_prefix_tenant(self, address, tenant_id, prefix_is_detected, default_vrf_id):
|
||||||
"""Assign a tenant, choose a VRF, and ask before creating a missing prefix."""
|
"""Assign a tenant and apply the previously confirmed network import plan."""
|
||||||
if not hasattr(self, "synced_prefixes"):
|
if not hasattr(self, "synced_prefixes"):
|
||||||
self.synced_prefixes = set()
|
self.synced_prefixes = set()
|
||||||
if not hasattr(self, "prefix_decisions"):
|
if not hasattr(self, "prefix_plans"):
|
||||||
self.prefix_decisions = {}
|
self.prefix_plans = []
|
||||||
parsed_interface = ipaddress.ip_interface(address)
|
parsed_interface = ipaddress.ip_interface(address)
|
||||||
host_address = parsed_interface.ip
|
host_address = parsed_interface.ip
|
||||||
network = str(parsed_interface.network)
|
network = str(parsed_interface.network)
|
||||||
vrf_id = default_vrf_id
|
vrf_id = default_vrf_id
|
||||||
|
|
||||||
|
for existing_prefix, existing_network, existing_vrf_id in getattr(self, "preexisting_prefixes", []):
|
||||||
|
if host_address in ipaddress.ip_network(existing_network):
|
||||||
|
existing_prefix.update({"tenant": tenant_id})
|
||||||
|
self.synced_prefixes.add((existing_network, existing_vrf_id))
|
||||||
|
self.log(f"Vorhandenes Netzwerk wiederverwendet: {existing_network}")
|
||||||
|
return existing_vrf_id
|
||||||
|
|
||||||
for cached_network, cached_vrf in self.synced_prefixes:
|
for cached_network, cached_vrf in self.synced_prefixes:
|
||||||
if host_address in ipaddress.ip_network(cached_network):
|
if host_address in ipaddress.ip_network(cached_network):
|
||||||
return cached_vrf
|
return cached_vrf
|
||||||
@@ -1511,40 +1780,18 @@ class NetBoxVMImporter:
|
|||||||
self.synced_prefixes.add((existing_network, existing_vrf_id))
|
self.synced_prefixes.add((existing_network, existing_vrf_id))
|
||||||
self.log(f"Vorhandenes Netzwerk wiederverwendet: {existing_network}")
|
self.log(f"Vorhandenes Netzwerk wiederverwendet: {existing_network}")
|
||||||
return existing_vrf_id
|
return existing_vrf_id
|
||||||
decision = self.prefix_decisions.get(cache_key)
|
matching_plans = [
|
||||||
needs_decision = cache_key not in self.prefix_decisions
|
decision for decision in self.prefix_plans
|
||||||
if decision is not None and host_address not in ipaddress.ip_network(decision["network"]):
|
if host_address in ipaddress.ip_network(decision["network"])
|
||||||
needs_decision = True
|
]
|
||||||
if needs_decision:
|
if not matching_plans:
|
||||||
tenant_vrfs = self.tenant_vrfs(tenant_id)
|
self.log(f"Präfix für {host_address} nicht angelegt (Netzwerkplan)")
|
||||||
tenant_name = next(
|
|
||||||
(
|
|
||||||
name for name, mapped_id in getattr(self, "tenant_map", {}).items()
|
|
||||||
if mapped_id == tenant_id
|
|
||||||
),
|
|
||||||
"Mandant",
|
|
||||||
)
|
|
||||||
dialog = PrefixCreationDialog(
|
|
||||||
self.root,
|
|
||||||
address,
|
|
||||||
detected_prefix=prefix_is_detected,
|
|
||||||
vrfs=tenant_vrfs,
|
|
||||||
default_vrf_id=vrf_id,
|
|
||||||
tenant_name=tenant_name,
|
|
||||||
)
|
|
||||||
self.prefix_decisions[cache_key] = dialog.result
|
|
||||||
decision = self.prefix_decisions[cache_key]
|
|
||||||
if decision is None:
|
|
||||||
self.log(f"Präfix für {host_address} nicht angelegt (Benutzerauswahl)")
|
|
||||||
return vrf_id
|
return vrf_id
|
||||||
|
decision = max(
|
||||||
network = decision["network"]
|
matching_plans,
|
||||||
if decision.get("create_vrf"):
|
key=lambda item: ipaddress.ip_network(item["network"]).prefixlen,
|
||||||
decision["vrf_id"] = self.get_or_create_tenant_vrf(
|
|
||||||
decision["vrf_name"],
|
|
||||||
tenant_id,
|
|
||||||
)
|
)
|
||||||
decision["create_vrf"] = False
|
network = decision["network"]
|
||||||
vrf_id = decision["vrf_id"]
|
vrf_id = decision["vrf_id"]
|
||||||
cache_key = (network, vrf_id)
|
cache_key = (network, vrf_id)
|
||||||
selected_candidates = self.find_prefixes_in_vrf(network, vrf_id)
|
selected_candidates = self.find_prefixes_in_vrf(network, vrf_id)
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
Reference in New Issue
Block a user