pygui implemented mac config and fixed issue with manually assigning mac addresses

This commit is contained in:
Blake Harnden 2020-04-22 23:00:07 -07:00
parent 3394f0240a
commit 7054e606ae
5 changed files with 61 additions and 24 deletions

View file

@ -41,6 +41,7 @@ DEFAULT_IP4S = ["10.0.0.0", "192.168.0.0", "172.16.0.0"]
DEFAULT_IP4 = DEFAULT_IP4S[0] DEFAULT_IP4 = DEFAULT_IP4S[0]
DEFAULT_IP6S = ["2001::", "2002::", "a::"] DEFAULT_IP6S = ["2001::", "2002::", "a::"]
DEFAULT_IP6 = DEFAULT_IP6S[0] DEFAULT_IP6 = DEFAULT_IP6S[0]
DEFAULT_MAC = "00:00:00:aa:00:00"
class IndentDumper(yaml.Dumper): class IndentDumper(yaml.Dumper):
@ -113,6 +114,7 @@ def check_directory():
"ip4s": DEFAULT_IP4S, "ip4s": DEFAULT_IP4S,
"ip6s": DEFAULT_IP6S, "ip6s": DEFAULT_IP6S,
}, },
"mac": DEFAULT_MAC,
} }
save(config) save(config)

View file

@ -483,7 +483,17 @@ class CoreClient:
self.app.after(0, show_grpc_error, e, self.app, self.app) self.app.after(0, show_grpc_error, e, self.app, self.app)
def start_session(self) -> core_pb2.StartSessionResponse: def start_session(self) -> core_pb2.StartSessionResponse:
self.interfaces_manager.reset_mac()
nodes = [x.core_node for x in self.canvas_nodes.values()] nodes = [x.core_node for x in self.canvas_nodes.values()]
links = []
for edge in self.links.values():
link = edge.link
logging.info("link: %s", link)
if link.HasField("interface_one") and not link.interface_one.mac:
link.interface_one.mac = self.interfaces_manager.next_mac()
if link.HasField("interface_two") and not link.interface_two.mac:
link.interface_two.mac = self.interfaces_manager.next_mac()
links.append(link)
links = [x.link for x in self.links.values()] links = [x.link for x in self.links.values()]
wlan_configs = self.get_wlan_configs_proto() wlan_configs = self.get_wlan_configs_proto()
mobility_configs = self.get_mobility_configs_proto() mobility_configs = self.get_mobility_configs_proto()
@ -849,7 +859,6 @@ class CoreClient:
ip6=ip6, ip6=ip6,
ip6mask=ip6_mask, ip6mask=ip6_mask,
) )
canvas_node.interfaces.append(interface)
logging.debug( logging.debug(
"create node(%s) interface(%s) IPv4(%s) IPv6(%s)", "create node(%s) interface(%s) IPv4(%s) IPv6(%s)",
node.name, node.name,
@ -875,13 +884,11 @@ class CoreClient:
src_interface = None src_interface = None
if NodeUtils.is_container_node(src_node.type): if NodeUtils.is_container_node(src_node.type):
src_interface = self.create_interface(canvas_src_node) src_interface = self.create_interface(canvas_src_node)
edge.src_interface = src_interface
self.interface_to_edge[(src_node.id, src_interface.id)] = edge.token self.interface_to_edge[(src_node.id, src_interface.id)] = edge.token
dst_interface = None dst_interface = None
if NodeUtils.is_container_node(dst_node.type): if NodeUtils.is_container_node(dst_node.type):
dst_interface = self.create_interface(canvas_dst_node) dst_interface = self.create_interface(canvas_dst_node)
edge.dst_interface = dst_interface
self.interface_to_edge[(dst_node.id, dst_interface.id)] = edge.token self.interface_to_edge[(dst_node.id, dst_interface.id)] = edge.token
link = core_pb2.Link( link = core_pb2.Link(
@ -891,6 +898,12 @@ class CoreClient:
interface_one=src_interface, interface_one=src_interface,
interface_two=dst_interface, interface_two=dst_interface,
) )
if src_interface:
edge.src_interface = link.interface_one
canvas_src_node.interfaces.append(link.interface_one)
if dst_interface:
edge.dst_interface = link.interface_two
canvas_dst_node.interfaces.append(link.interface_two)
edge.set_link(link) edge.set_link(link)
self.links[edge.token] = edge self.links[edge.token] = edge
logging.info("Add link between %s and %s", src_node.name, dst_node.name) logging.info("Add link between %s and %s", src_node.name, dst_node.name)

View file

@ -1,6 +1,10 @@
from tkinter import ttk import tkinter as tk
from tkinter import messagebox, ttk
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import netaddr
from core.gui import appconfig
from core.gui.dialogs.dialog import Dialog from core.gui.dialogs.dialog import Dialog
from core.gui.themes import PADX, PADY from core.gui.themes import PADX, PADY
@ -11,6 +15,8 @@ if TYPE_CHECKING:
class MacConfigDialog(Dialog): class MacConfigDialog(Dialog):
def __init__(self, master: "Application", app: "Application") -> None: def __init__(self, master: "Application", app: "Application") -> None:
super().__init__(master, app, "MAC Configuration", modal=True) super().__init__(master, app, "MAC Configuration", modal=True)
mac = self.app.guiconfig.get("mac", appconfig.DEFAULT_MAC)
self.mac_var = tk.StringVar(value=mac)
self.draw() self.draw()
def draw(self) -> None: def draw(self) -> None:
@ -32,7 +38,7 @@ class MacConfigDialog(Dialog):
frame.grid(stick="ew", pady=PADY) frame.grid(stick="ew", pady=PADY)
label = ttk.Label(frame, text="Starting MAC") label = ttk.Label(frame, text="Starting MAC")
label.grid(row=0, column=0, sticky="ew", padx=PADX) label.grid(row=0, column=0, sticky="ew", padx=PADX)
entry = ttk.Entry(frame) entry = ttk.Entry(frame, textvariable=self.mac_var)
entry.grid(row=0, column=1, sticky="ew") entry.grid(row=0, column=1, sticky="ew")
# draw buttons # draw buttons
@ -46,4 +52,10 @@ class MacConfigDialog(Dialog):
button.grid(row=0, column=1, sticky="ew") button.grid(row=0, column=1, sticky="ew")
def click_save(self) -> None: def click_save(self) -> None:
pass mac = self.mac_var.get()
if not netaddr.valid_mac(mac):
messagebox.showerror("MAC Error", f"{mac} is an invalid mac")
else:
self.app.core.interfaces_manager.mac = netaddr.EUI(mac)
self.app.guiconfig["mac"] = mac
self.app.save_config()

View file

@ -70,16 +70,12 @@ def check_ip4(parent, name: str, value: str) -> bool:
return True return True
def mac_auto(is_auto: tk.BooleanVar, entry: ttk.Entry): def mac_auto(is_auto: tk.BooleanVar, entry: ttk.Entry, mac: tk.StringVar) -> None:
logging.info("mac auto clicked")
if is_auto.get(): if is_auto.get():
logging.info("disabling mac") mac.set("")
entry.delete(0, tk.END)
entry.insert(tk.END, "")
entry.config(state=tk.DISABLED) entry.config(state=tk.DISABLED)
else: else:
entry.delete(0, tk.END) mac.set("00:00:00:00:00:00")
entry.insert(tk.END, "00:00:00:00:00:00")
entry.config(state=tk.NORMAL) entry.config(state=tk.NORMAL)
@ -252,7 +248,7 @@ class NodeConfigDialog(Dialog):
mac = tk.StringVar(value=interface.mac) mac = tk.StringVar(value=interface.mac)
entry = ttk.Entry(tab, textvariable=mac, state=state) entry = ttk.Entry(tab, textvariable=mac, state=state)
entry.grid(row=row, column=2, sticky="ew") entry.grid(row=row, column=2, sticky="ew")
func = partial(mac_auto, is_auto, entry) func = partial(mac_auto, is_auto, entry, mac)
checkbutton.config(command=func) checkbutton.config(command=func)
row += 1 row += 1
@ -283,7 +279,7 @@ class NodeConfigDialog(Dialog):
frame.columnconfigure(0, weight=1) frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=1) frame.columnconfigure(1, weight=1)
button = ttk.Button(frame, text="Apply", command=self.config_apply) button = ttk.Button(frame, text="Apply", command=self.click_apply)
button.grid(row=0, column=0, padx=PADX, sticky="ew") button.grid(row=0, column=0, padx=PADX, sticky="ew")
button = ttk.Button(frame, text="Cancel", command=self.destroy) button = ttk.Button(frame, text="Cancel", command=self.destroy)
@ -302,7 +298,7 @@ class NodeConfigDialog(Dialog):
self.image_button.config(image=self.image) self.image_button.config(image=self.image)
self.image_file = file_path self.image_file = file_path
def config_apply(self): def click_apply(self):
error = False error = False
# update core node # update core node
@ -328,7 +324,6 @@ class NodeConfigDialog(Dialog):
ip4_net = data.ip4.get() ip4_net = data.ip4.get()
if not check_ip4(self, interface.name, ip4_net): if not check_ip4(self, interface.name, ip4_net):
error = True error = True
data.ip4.set(f"{interface.ip4}/{interface.ip4mask}")
break break
if ip4_net: if ip4_net:
ip4, ip4mask = ip4_net.split("/") ip4, ip4mask = ip4_net.split("/")
@ -342,7 +337,6 @@ class NodeConfigDialog(Dialog):
ip6_net = data.ip6.get() ip6_net = data.ip6.get()
if not check_ip6(self, interface.name, ip6_net): if not check_ip6(self, interface.name, ip6_net):
error = True error = True
data.ip6.set(f"{interface.ip6}/{interface.ip6mask}")
break break
if ip6_net: if ip6_net:
ip6, ip6mask = ip6_net.split("/") ip6, ip6mask = ip6_net.split("/")
@ -353,13 +347,13 @@ class NodeConfigDialog(Dialog):
interface.ip6mask = ip6mask interface.ip6mask = ip6mask
mac = data.mac.get() mac = data.mac.get()
if mac and not netaddr.valid_mac(mac): auto_mac = data.is_auto.get()
if not auto_mac and not netaddr.valid_mac(mac):
title = f"MAC Error for {interface.name}" title = f"MAC Error for {interface.name}"
messagebox.showerror(title, "Invalid MAC Address") messagebox.showerror(title, "Invalid MAC Address")
error = True error = True
data.mac.set(interface.mac)
break break
else: elif not auto_mac:
mac = netaddr.EUI(mac) mac = netaddr.EUI(mac)
mac.dialect = netaddr.mac_unix_expanded mac.dialect = netaddr.mac_unix_expanded
interface.mac = str(mac) interface.mac = str(mac)

View file

@ -2,8 +2,10 @@ import logging
import random import random
from typing import TYPE_CHECKING, Set, Union from typing import TYPE_CHECKING, Set, Union
from netaddr import IPNetwork import netaddr
from netaddr import EUI, IPNetwork
from core.gui import appconfig
from core.gui.nodeutils import NodeUtils from core.gui.nodeutils import NodeUtils
if TYPE_CHECKING: if TYPE_CHECKING:
@ -35,12 +37,15 @@ class InterfaceManager:
def __init__(self, app: "Application") -> None: def __init__(self, app: "Application") -> None:
self.app = app self.app = app
ip_config = self.app.guiconfig.get("ips", {}) ip_config = self.app.guiconfig.get("ips", {})
ip4 = ip_config.get("ip4", "10.0.0.0") ip4 = ip_config.get("ip4", appconfig.DEFAULT_IP4)
ip6 = ip_config.get("ip6", "2001::") ip6 = ip_config.get("ip6", appconfig.DEFAULT_IP6)
self.ip4_mask = 24 self.ip4_mask = 24
self.ip6_mask = 64 self.ip6_mask = 64
self.ip4_subnets = IPNetwork(f"{ip4}/{self.ip4_mask}") self.ip4_subnets = IPNetwork(f"{ip4}/{self.ip4_mask}")
self.ip6_subnets = IPNetwork(f"{ip6}/{self.ip6_mask}") self.ip6_subnets = IPNetwork(f"{ip6}/{self.ip6_mask}")
mac = self.app.guiconfig.get("mac", appconfig.DEFAULT_MAC)
self.mac = EUI(mac)
self.current_mac = None
self.current_subnets = None self.current_subnets = None
def update_ips(self, ip4: str, ip6: str) -> None: def update_ips(self, ip4: str, ip6: str) -> None:
@ -48,6 +53,17 @@ class InterfaceManager:
self.ip4_subnets = IPNetwork(f"{ip4}/{self.ip4_mask}") self.ip4_subnets = IPNetwork(f"{ip4}/{self.ip4_mask}")
self.ip6_subnets = IPNetwork(f"{ip6}/{self.ip6_mask}") self.ip6_subnets = IPNetwork(f"{ip6}/{self.ip6_mask}")
def reset_mac(self) -> None:
self.current_mac = self.mac
self.current_mac.dialect = netaddr.mac_unix_expanded
def next_mac(self) -> str:
mac = str(self.current_mac)
value = self.current_mac.value + 1
self.current_mac = EUI(value)
self.current_mac.dialect = netaddr.mac_unix_expanded
return mac
def next_subnets(self) -> Subnets: def next_subnets(self) -> Subnets:
# define currently used subnets # define currently used subnets
used_subnets = set() used_subnets = set()