Merge pull request #374 from coreemu/coretk-enhance/wlanlink-runtime-deletion

Coretk enhance/wlanlink runtime deletion
This commit is contained in:
bharnden 2020-02-24 10:30:30 -08:00 committed by GitHub
commit 8b544d98d8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 115 additions and 6 deletions

View file

@ -1,7 +1,3 @@
"""
wlan configuration
"""
from tkinter import ttk from tkinter import ttk
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
@ -16,6 +12,9 @@ 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
RANGE_COLOR = "#009933"
RANGE_WIDTH = 3
class WlanConfigDialog(Dialog): class WlanConfigDialog(Dialog):
def __init__( def __init__(
@ -27,15 +26,29 @@ class WlanConfigDialog(Dialog):
self.canvas_node = canvas_node self.canvas_node = canvas_node
self.node = canvas_node.core_node self.node = canvas_node.core_node
self.config_frame = None self.config_frame = None
self.range_entry = None
self.has_error = False self.has_error = False
self.canvas = app.canvas
self.ranges = {}
self.positive_int = self.app.master.register(self.validate_and_update)
try: try:
self.config = self.app.core.get_wlan_config(self.node.id) self.config = self.app.core.get_wlan_config(self.node.id)
self.init_draw_range()
self.draw() self.draw()
except grpc.RpcError as e: except grpc.RpcError as e:
show_grpc_error(e, self.app, self.app) show_grpc_error(e, self.app, self.app)
self.has_error = True self.has_error = True
self.destroy() self.destroy()
def init_draw_range(self):
if self.canvas_node.id in self.canvas.wireless_network:
for cid in self.canvas.wireless_network[self.canvas_node.id]:
x, y = self.canvas.coords(cid)
range_id = self.canvas.create_oval(
x, y, x, y, width=RANGE_WIDTH, outline=RANGE_COLOR, tags="range"
)
self.ranges[cid] = range_id
def draw(self): def draw(self):
self.top.columnconfigure(0, weight=1) self.top.columnconfigure(0, weight=1)
self.top.rowconfigure(0, weight=1) self.top.rowconfigure(0, weight=1)
@ -43,6 +56,7 @@ class WlanConfigDialog(Dialog):
self.config_frame.draw_config() self.config_frame.draw_config()
self.config_frame.grid(sticky="nsew", pady=PADY) self.config_frame.grid(sticky="nsew", pady=PADY)
self.draw_apply_buttons() self.draw_apply_buttons()
self.top.bind("<Destroy>", self.remove_ranges)
def draw_apply_buttons(self): def draw_apply_buttons(self):
""" """
@ -53,6 +67,11 @@ class WlanConfigDialog(Dialog):
for i in range(2): for i in range(2):
frame.columnconfigure(i, weight=1) frame.columnconfigure(i, weight=1)
self.range_entry = self.config_frame.winfo_children()[0].frame.winfo_children()[
-1
]
self.range_entry.config(validatecommand=(self.positive_int, "%P"))
button = ttk.Button(frame, text="Apply", command=self.click_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")
@ -68,4 +87,35 @@ class WlanConfigDialog(Dialog):
if self.app.core.is_runtime(): if self.app.core.is_runtime():
session_id = self.app.core.session_id session_id = self.app.core.session_id
self.app.core.client.set_wlan_config(session_id, self.node.id, config) self.app.core.client.set_wlan_config(session_id, self.node.id, config)
self.remove_ranges()
self.destroy() self.destroy()
def remove_ranges(self, event=None):
for cid in self.canvas.find_withtag("range"):
self.canvas.delete(cid)
self.ranges.clear()
def validate_and_update(self, s: str) -> bool:
"""
custom validation to also redraw the mdr ranges when the range value changes
"""
if len(s) == 0:
return True
try:
int_value = int(s)
if int_value >= 0:
net_range = int_value * self.canvas.ratio
if self.canvas_node.id in self.canvas.wireless_network:
for cid in self.canvas.wireless_network[self.canvas_node.id]:
x, y = self.canvas.coords(cid)
self.canvas.coords(
self.ranges[cid],
x - net_range,
y - net_range,
x + net_range,
y + net_range,
)
return True
return False
except ValueError:
return False

View file

@ -186,6 +186,17 @@ class CanvasEdge:
dst_node_type = dst_node.core_node.type dst_node_type = dst_node.core_node.type
is_src_wireless = NodeUtils.is_wireless_node(src_node_type) is_src_wireless = NodeUtils.is_wireless_node(src_node_type)
is_dst_wireless = NodeUtils.is_wireless_node(dst_node_type) is_dst_wireless = NodeUtils.is_wireless_node(dst_node_type)
# update the wlan/EMANE network
wlan_network = self.canvas.wireless_network
if is_src_wireless and not is_dst_wireless:
if self.src not in wlan_network:
wlan_network[self.src] = set()
wlan_network[self.src].add(self.dst)
elif not is_src_wireless and is_dst_wireless:
if self.dst not in wlan_network:
wlan_network[self.dst] = set()
wlan_network[self.dst].add(self.src)
return is_src_wireless or is_dst_wireless return is_src_wireless or is_dst_wireless
def check_wireless(self): def check_wireless(self):

View file

@ -42,6 +42,10 @@ class CanvasGraph(tk.Canvas):
self.edges = {} self.edges = {}
self.shapes = {} self.shapes = {}
self.wireless_edges = {} self.wireless_edges = {}
# map wireless/EMANE node to the set of MDRs connected to that node
self.wireless_network = {}
self.drawing_edge = None self.drawing_edge = None
self.grid = None self.grid = None
self.shape_drawing = False self.shape_drawing = False
@ -113,6 +117,7 @@ class CanvasGraph(tk.Canvas):
self.edges.clear() self.edges.clear()
self.shapes.clear() self.shapes.clear()
self.wireless_edges.clear() self.wireless_edges.clear()
self.wireless_network.clear()
self.drawing_edge = None self.drawing_edge = None
self.draw_session(session) self.draw_session(session)

View file

@ -17,7 +17,7 @@ from core.gui.errors import show_grpc_error
from core.gui.graph import tags from core.gui.graph import tags
from core.gui.graph.tooltip import CanvasTooltip from core.gui.graph.tooltip import CanvasTooltip
from core.gui.images import ImageEnum, Images from core.gui.images import ImageEnum, Images
from core.gui.nodeutils import ANTENNA_SIZE, NodeUtils from core.gui.nodeutils import ANTENNA_SIZE, EdgeUtils, NodeUtils
if TYPE_CHECKING: if TYPE_CHECKING:
from core.gui.app import Application from core.gui.app import Application
@ -66,9 +66,48 @@ class CanvasNode:
def delete(self): def delete(self):
logging.debug("Delete canvas node for %s", self.core_node) logging.debug("Delete canvas node for %s", self.core_node)
# if node is wlan, EMANE type, remove any existing wireless links between nodes connetect to this node
if NodeUtils.is_wireless_node(self.core_node.type):
nodes = []
for edge in self.edges:
token = edge.token
if self.id == token[0]:
nodes.append(token[1])
else:
nodes.append(token[0])
for i in range(len(nodes)):
for j in range(i + 1, len(nodes)):
token = EdgeUtils.get_token(nodes[i], nodes[j])
wireless_edge = self.canvas.wireless_edges.pop(token, None)
if wireless_edge:
self.canvas.nodes[nodes[i]].wireless_edges.remove(wireless_edge)
self.canvas.nodes[nodes[j]].wireless_edges.remove(wireless_edge)
self.canvas.delete(wireless_edge.id)
else:
logging.debug("%s is not a wireless edge", token)
# if node is MDR, remove wireless links to other MDRs
elif NodeUtils.is_mdr_node(self.core_node.type, self.core_node.model):
for wireless_edge in self.wireless_edges:
token = wireless_edge.token
other = token[0]
if other == self.id:
other = token[1]
self.canvas.nodes[other].wireless_edges.discard(wireless_edge)
try:
wlan_edge = self.canvas.wireless_edges.pop(token)
self.canvas.delete(wlan_edge.id)
except KeyError:
logging.error(
"wireless link not found, potentially multiple wireless link issue"
)
self.delete_antennas()
self.wireless_edges.clear()
self.canvas.delete(self.id) self.canvas.delete(self.id)
self.canvas.delete(self.text_id) self.canvas.delete(self.text_id)
self.delete_antennas()
def add_antenna(self): def add_antenna(self):
x, y = self.canvas.coords(self.id) x, y = self.canvas.coords(self.id)

View file

@ -90,6 +90,10 @@ class NodeUtils:
def is_rj45_node(cls, node_type: NodeType) -> bool: def is_rj45_node(cls, node_type: NodeType) -> bool:
return node_type in cls.RJ45_NODES return node_type in cls.RJ45_NODES
@classmethod
def is_mdr_node(cls, node_type: NodeType, model: str) -> bool:
return cls.is_container_node(node_type) and model == "mdr"
@classmethod @classmethod
def node_icon( def node_icon(
cls, cls,