From 0d4a86f10e69a5409822fc5ff1b165b083275936 Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Wed, 4 Mar 2020 11:38:24 -0800 Subject: [PATCH] updated new gui to properly update modified addresses for nodes, added validation for ip4/ip6, fixed redrawing edge labels when node addresses change --- daemon/core/gui/dialogs/nodeconfig.py | 86 +++++++++++++++++++++++++-- daemon/core/gui/graph/edges.py | 13 +++- daemon/core/gui/graph/node.py | 2 + 3 files changed, 94 insertions(+), 7 deletions(-) diff --git a/daemon/core/gui/dialogs/nodeconfig.py b/daemon/core/gui/dialogs/nodeconfig.py index 7db65dc7..fcca2896 100644 --- a/daemon/core/gui/dialogs/nodeconfig.py +++ b/daemon/core/gui/dialogs/nodeconfig.py @@ -1,9 +1,11 @@ import logging import tkinter as tk from functools import partial -from tkinter import ttk +from tkinter import messagebox, ttk from typing import TYPE_CHECKING +import netaddr + from core.gui import nodeutils from core.gui.appconfig import ICONS_PATH from core.gui.dialogs.dialog import Dialog @@ -18,6 +20,58 @@ if TYPE_CHECKING: from core.gui.graph.node import CanvasNode +def check_ip6(parent, name: str, value: str) -> bool: + title = f"IP6 Error for {name}" + if not value: + messagebox.showerror(title, "Empty Value", parent=parent) + return False + values = value.split("/") + if len(values) != 2: + messagebox.showerror( + title, "Must be in the format address/prefix", parent=parent + ) + return False + addr, mask = values + if not netaddr.valid_ipv6(addr): + messagebox.showerror(title, "Invalid IP6 address", parent=parent) + return False + try: + mask = int(mask) + if not (0 <= mask <= 128): + messagebox.showerror(title, "Mask must be between 0-128", parent=parent) + return False + except ValueError: + messagebox.showerror(title, "Invalid Mask", parent=parent) + return False + return True + + +def check_ip4(parent, name: str, value: str) -> bool: + title = f"IP4 Error for {name}" + if not value: + messagebox.showerror(title, "Empty Value", parent=parent) + return False + values = value.split("/") + if len(values) != 2: + messagebox.showerror( + title, "Must be in the format address/prefix", parent=parent + ) + return False + addr, mask = values + if not netaddr.valid_ipv4(addr): + messagebox.showerror(title, "Invalid IP4 address", parent=parent) + return False + try: + mask = int(mask) + if not (0 <= mask <= 32): + messagebox.showerror(title, "Mask must be between 0-32", parent=parent) + return False + except ValueError: + messagebox.showerror(title, "Invalid mask", parent=parent) + return False + return True + + def mac_auto(is_auto: tk.BooleanVar, entry: ttk.Entry): logging.info("mac auto clicked") if is_auto.get(): @@ -203,7 +257,6 @@ class NodeConfigDialog(Dialog): label.grid(row=row, column=0, padx=PADX, pady=PADY) ip4 = tk.StringVar(value=f"{interface.ip4}/{interface.ip4mask}") entry = ttk.Entry(tab, textvariable=ip4) - entry.bind("", self.app.validation.ip_focus_out) entry.grid(row=row, column=1, columnspan=2, sticky="ew") row += 1 @@ -211,7 +264,6 @@ class NodeConfigDialog(Dialog): label.grid(row=row, column=0, padx=PADX, pady=PADY) ip6 = tk.StringVar(value=f"{interface.ip6}/{interface.ip6mask}") entry = ttk.Entry(tab, textvariable=ip6) - entry.bind("", self.app.validation.ip_focus_out) entry.grid(row=row, column=1, columnspan=2, sticky="ew") self.interfaces[interface.id] = InterfaceData(is_auto, mac, ip4, ip6) @@ -240,6 +292,8 @@ class NodeConfigDialog(Dialog): self.image_file = file_path def config_apply(self): + error = False + # update core node self.node.name = self.name.get() if NodeUtils.is_image_node(self.node.type): @@ -255,9 +309,31 @@ class NodeConfigDialog(Dialog): # update canvas node self.canvas_node.image = self.image + # update node interface data + for interface in self.canvas_node.interfaces: + data = self.interfaces[interface.id] + if check_ip4(self, interface.name, data.ip4.get()): + ip4, ip4mask = data.ip4.get().split("/") + interface.ip4 = ip4 + interface.ip4mask = int(ip4mask) + else: + error = True + data.ip4.set(f"{interface.ip4}/{interface.ip4mask}") + break + if check_ip6(self, interface.name, data.ip6.get()): + ip6, ip6mask = data.ip6.get().split("/") + interface.ip6 = ip6 + interface.ip6mask = int(ip6mask) + interface.mac = data.mac.get() + else: + error = True + data.ip6.set(f"{interface.ip6}/{interface.ip6mask}") + break + # redraw - self.canvas_node.redraw() - self.destroy() + if not error: + self.canvas_node.redraw() + self.destroy() def interface_select(self, event: tk.Event): listbox = event.widget diff --git a/daemon/core/gui/graph/edges.py b/daemon/core/gui/graph/edges.py index 0659767d..fb5f64eb 100644 --- a/daemon/core/gui/graph/edges.py +++ b/daemon/core/gui/graph/edges.py @@ -107,8 +107,7 @@ class CanvasEdge: y = (y1 + y2) / 2 return x, y - def draw_labels(self): - x1, y1, x2, y2 = self.get_coordinates() + def create_labels(self): label_one = None if self.link.HasField("interface_one"): label_one = ( @@ -121,6 +120,11 @@ class CanvasEdge: f"{self.link.interface_two.ip4}/{self.link.interface_two.ip4mask}\n" f"{self.link.interface_two.ip6}/{self.link.interface_two.ip6mask}\n" ) + return label_one, label_two + + def draw_labels(self): + x1, y1, x2, y2 = self.get_coordinates() + label_one, label_two = self.create_labels() self.text_src = self.canvas.create_text( x1, y1, @@ -138,6 +142,11 @@ class CanvasEdge: tags=tags.LINK_INFO, ) + def redraw(self): + label_one, label_two = self.create_labels() + self.canvas.itemconfig(self.text_src, text=label_one) + self.canvas.itemconfig(self.text_dst, text=label_two) + def update_labels(self): """ Move edge labels based on current position. diff --git a/daemon/core/gui/graph/node.py b/daemon/core/gui/graph/node.py index 3ed5b1d9..7ae64eac 100644 --- a/daemon/core/gui/graph/node.py +++ b/daemon/core/gui/graph/node.py @@ -107,6 +107,8 @@ class CanvasNode: def redraw(self): self.canvas.itemconfig(self.id, image=self.image) self.canvas.itemconfig(self.text_id, text=self.core_node.name) + for edge in self.edges: + edge.redraw() def _get_label_y(self): image_box = self.canvas.bbox(self.id)