pygui: add support to rename interfaces in the node config dialog, some small cleanup to interface validation
This commit is contained in:
parent
5b93c2d7ac
commit
836e929fbc
1 changed files with 88 additions and 42 deletions
|
@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Dict, Optional
|
||||||
import netaddr
|
import netaddr
|
||||||
from PIL.ImageTk import PhotoImage
|
from PIL.ImageTk import PhotoImage
|
||||||
|
|
||||||
from core.api.grpc.wrappers import Node
|
from core.api.grpc.wrappers import Interface, Node
|
||||||
from core.gui import nodeutils, validation
|
from core.gui import nodeutils, validation
|
||||||
from core.gui.appconfig import ICONS_PATH
|
from core.gui.appconfig import ICONS_PATH
|
||||||
from core.gui.dialogs.dialog import Dialog
|
from core.gui.dialogs.dialog import Dialog
|
||||||
|
@ -21,8 +21,10 @@ if TYPE_CHECKING:
|
||||||
from core.gui.app import Application
|
from core.gui.app import Application
|
||||||
from core.gui.graph.node import CanvasNode
|
from core.gui.graph.node import CanvasNode
|
||||||
|
|
||||||
|
IFACE_NAME_LEN: int = 15
|
||||||
|
|
||||||
def check_ip6(parent, name: str, value: str) -> bool:
|
|
||||||
|
def check_ip6(parent: tk.BaseWidget, name: str, value: str) -> bool:
|
||||||
if not value:
|
if not value:
|
||||||
return True
|
return True
|
||||||
title = f"IP6 Error for {name}"
|
title = f"IP6 Error for {name}"
|
||||||
|
@ -47,7 +49,7 @@ def check_ip6(parent, name: str, value: str) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def check_ip4(parent, name: str, value: str) -> bool:
|
def check_ip4(parent: tk.BaseWidget, name: str, value: str) -> bool:
|
||||||
if not value:
|
if not value:
|
||||||
return True
|
return True
|
||||||
title = f"IP4 Error for {name}"
|
title = f"IP4 Error for {name}"
|
||||||
|
@ -84,16 +86,88 @@ def mac_auto(is_auto: tk.BooleanVar, entry: ttk.Entry, mac: tk.StringVar) -> Non
|
||||||
class InterfaceData:
|
class InterfaceData:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
name: tk.StringVar,
|
||||||
is_auto: tk.BooleanVar,
|
is_auto: tk.BooleanVar,
|
||||||
mac: tk.StringVar,
|
mac: tk.StringVar,
|
||||||
ip4: tk.StringVar,
|
ip4: tk.StringVar,
|
||||||
ip6: tk.StringVar,
|
ip6: tk.StringVar,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
self.name: tk.StringVar = name
|
||||||
self.is_auto: tk.BooleanVar = is_auto
|
self.is_auto: tk.BooleanVar = is_auto
|
||||||
self.mac: tk.StringVar = mac
|
self.mac: tk.StringVar = mac
|
||||||
self.ip4: tk.StringVar = ip4
|
self.ip4: tk.StringVar = ip4
|
||||||
self.ip6: tk.StringVar = ip6
|
self.ip6: tk.StringVar = ip6
|
||||||
|
|
||||||
|
def validate(self, parent: tk.BaseWidget, iface: Interface) -> bool:
|
||||||
|
valid_name = self._validate_name(parent, iface)
|
||||||
|
valid_ip4 = self._validate_ip4(parent, iface)
|
||||||
|
valid_ip6 = self._validate_ip6(parent, iface)
|
||||||
|
valid_mac = self._validate_mac(parent, iface)
|
||||||
|
return all([valid_name, valid_ip4, valid_ip6, valid_mac])
|
||||||
|
|
||||||
|
def _validate_name(self, parent: tk.BaseWidget, iface: Interface) -> bool:
|
||||||
|
name = self.name.get()
|
||||||
|
title = f"Interface Name Error for {iface.name}"
|
||||||
|
if not name:
|
||||||
|
messagebox.showerror(title, "Name cannot be empty", parent=parent)
|
||||||
|
return False
|
||||||
|
if len(name) > IFACE_NAME_LEN:
|
||||||
|
messagebox.showerror(
|
||||||
|
title,
|
||||||
|
f"Name cannot be greater than {IFACE_NAME_LEN} chars",
|
||||||
|
parent=parent,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
for x in name:
|
||||||
|
if x.isspace() or x == "/":
|
||||||
|
messagebox.showerror(
|
||||||
|
title, "Name cannot contain space or /", parent=parent
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
iface.name = name
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _validate_ip4(self, parent: tk.BaseWidget, iface: Interface) -> bool:
|
||||||
|
ip4_net = self.ip4.get()
|
||||||
|
if not check_ip4(parent, iface.name, ip4_net):
|
||||||
|
return False
|
||||||
|
if ip4_net:
|
||||||
|
ip4, ip4_mask = ip4_net.split("/")
|
||||||
|
ip4_mask = int(ip4_mask)
|
||||||
|
else:
|
||||||
|
ip4, ip4_mask = "", 0
|
||||||
|
iface.ip4 = ip4
|
||||||
|
iface.ip4_mask = ip4_mask
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _validate_ip6(self, parent: tk.BaseWidget, iface: Interface) -> bool:
|
||||||
|
ip6_net = self.ip6.get()
|
||||||
|
if not check_ip6(parent, iface.name, ip6_net):
|
||||||
|
return False
|
||||||
|
if ip6_net:
|
||||||
|
ip6, ip6_mask = ip6_net.split("/")
|
||||||
|
ip6_mask = int(ip6_mask)
|
||||||
|
else:
|
||||||
|
ip6, ip6_mask = "", 0
|
||||||
|
iface.ip6 = ip6
|
||||||
|
iface.ip6_mask = ip6_mask
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _validate_mac(self, parent: tk.BaseWidget, iface: Interface) -> bool:
|
||||||
|
mac = self.mac.get()
|
||||||
|
auto_mac = self.is_auto.get()
|
||||||
|
if auto_mac:
|
||||||
|
iface.mac = None
|
||||||
|
else:
|
||||||
|
if not netaddr.valid_mac(mac):
|
||||||
|
title = f"MAC Error for {iface.name}"
|
||||||
|
messagebox.showerror(title, "Invalid MAC Address", parent=parent)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
mac = netaddr.EUI(mac, dialect=netaddr.mac_unix_expanded)
|
||||||
|
iface.mac = str(mac)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class NodeConfigDialog(Dialog):
|
class NodeConfigDialog(Dialog):
|
||||||
def __init__(self, app: "Application", canvas_node: "CanvasNode") -> None:
|
def __init__(self, app: "Application", canvas_node: "CanvasNode") -> None:
|
||||||
|
@ -229,6 +303,14 @@ class NodeConfigDialog(Dialog):
|
||||||
button.grid(row=row, sticky=tk.EW, columnspan=3, pady=PADY)
|
button.grid(row=row, sticky=tk.EW, columnspan=3, pady=PADY)
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
|
label = ttk.Label(tab, text="Name")
|
||||||
|
label.grid(row=row, column=0, padx=PADX, pady=PADY)
|
||||||
|
name = tk.StringVar(value=iface.name)
|
||||||
|
entry = ttk.Entry(tab, textvariable=name, state=state)
|
||||||
|
entry.var = name
|
||||||
|
entry.grid(row=row, column=1, columnspan=2, sticky=tk.EW)
|
||||||
|
row += 1
|
||||||
|
|
||||||
label = ttk.Label(tab, text="MAC")
|
label = ttk.Label(tab, text="MAC")
|
||||||
label.grid(row=row, column=0, padx=PADX, pady=PADY)
|
label.grid(row=row, column=0, padx=PADX, pady=PADY)
|
||||||
auto_set = not iface.mac
|
auto_set = not iface.mac
|
||||||
|
@ -267,7 +349,7 @@ class NodeConfigDialog(Dialog):
|
||||||
entry = ttk.Entry(tab, textvariable=ip6, state=state)
|
entry = ttk.Entry(tab, textvariable=ip6, state=state)
|
||||||
entry.grid(row=row, column=1, columnspan=2, sticky=tk.EW)
|
entry.grid(row=row, column=1, columnspan=2, sticky=tk.EW)
|
||||||
|
|
||||||
self.ifaces[iface.id] = InterfaceData(is_auto, mac, ip4, ip6)
|
self.ifaces[iface.id] = InterfaceData(name, is_auto, mac, ip4, ip6)
|
||||||
|
|
||||||
def draw_buttons(self) -> None:
|
def draw_buttons(self) -> None:
|
||||||
frame = ttk.Frame(self.top)
|
frame = ttk.Frame(self.top)
|
||||||
|
@ -313,45 +395,9 @@ class NodeConfigDialog(Dialog):
|
||||||
# update node interface data
|
# update node interface data
|
||||||
for iface in self.canvas_node.ifaces.values():
|
for iface in self.canvas_node.ifaces.values():
|
||||||
data = self.ifaces[iface.id]
|
data = self.ifaces[iface.id]
|
||||||
|
error = not data.validate(self, iface)
|
||||||
# validate ip4
|
if error:
|
||||||
ip4_net = data.ip4.get()
|
|
||||||
if not check_ip4(self, iface.name, ip4_net):
|
|
||||||
error = True
|
|
||||||
break
|
break
|
||||||
if ip4_net:
|
|
||||||
ip4, ip4_mask = ip4_net.split("/")
|
|
||||||
ip4_mask = int(ip4_mask)
|
|
||||||
else:
|
|
||||||
ip4, ip4_mask = "", 0
|
|
||||||
iface.ip4 = ip4
|
|
||||||
iface.ip4_mask = ip4_mask
|
|
||||||
|
|
||||||
# validate ip6
|
|
||||||
ip6_net = data.ip6.get()
|
|
||||||
if not check_ip6(self, iface.name, ip6_net):
|
|
||||||
error = True
|
|
||||||
break
|
|
||||||
if ip6_net:
|
|
||||||
ip6, ip6_mask = ip6_net.split("/")
|
|
||||||
ip6_mask = int(ip6_mask)
|
|
||||||
else:
|
|
||||||
ip6, ip6_mask = "", 0
|
|
||||||
iface.ip6 = ip6
|
|
||||||
iface.ip6_mask = ip6_mask
|
|
||||||
|
|
||||||
mac = data.mac.get()
|
|
||||||
auto_mac = data.is_auto.get()
|
|
||||||
if auto_mac:
|
|
||||||
iface.mac = None
|
|
||||||
elif not auto_mac and not netaddr.valid_mac(mac):
|
|
||||||
title = f"MAC Error for {iface.name}"
|
|
||||||
messagebox.showerror(title, "Invalid MAC Address")
|
|
||||||
error = True
|
|
||||||
break
|
|
||||||
elif not auto_mac:
|
|
||||||
mac = netaddr.EUI(mac, dialect=netaddr.mac_unix_expanded)
|
|
||||||
iface.mac = str(mac)
|
|
||||||
|
|
||||||
# redraw
|
# redraw
|
||||||
if not error:
|
if not error:
|
||||||
|
|
Loading…
Add table
Reference in a new issue