updates to implement working observer widgets

This commit is contained in:
Blake Harnden 2019-11-11 13:23:02 -08:00
parent 18c9904d58
commit aa718817d0
5 changed files with 74 additions and 63 deletions

View file

@ -18,25 +18,14 @@ class CanvasTooltip:
"""
def __init__(
self,
canvas,
tag_or_id,
*,
bg="#FFFFEA",
pad=(5, 3, 5, 3),
text="canvas info",
waittime=400,
wraplength=250
self, canvas, *, bg="#FFFFEA", pad=(5, 3, 5, 3), waittime=400, wraplength=600
):
# in miliseconds, originally 500
self.waittime = waittime
# in pixels, originally 180
self.wraplength = wraplength
self.canvas = canvas
self.text = text
self.canvas.tag_bind(tag_or_id, "<Enter>", self.on_enter)
self.canvas.tag_bind(tag_or_id, "<Leave>", self.on_leave)
self.canvas.tag_bind(tag_or_id, "<ButtonPress>", self.on_leave)
self.text = tk.StringVar()
self.bg = bg
self.pad = pad
self.id = None
@ -61,18 +50,13 @@ class CanvasTooltip:
def show(self, event=None):
def tip_pos_calculator(canvas, label, *, tip_delta=(10, 5), pad=(5, 3, 5, 3)):
c = canvas
s_width, s_height = c.winfo_screenwidth(), c.winfo_screenheight()
width, height = (
pad[0] + label.winfo_reqwidth() + pad[2],
pad[1] + label.winfo_reqheight() + pad[3],
)
mouse_x, mouse_y = c.winfo_pointerxy()
x1, y1 = mouse_x + tip_delta[0], mouse_y + tip_delta[1]
x2, y2 = x1 + width, y1 + height
@ -84,20 +68,14 @@ class CanvasTooltip:
y_delta = 0
offscreen = (x_delta, y_delta) != (0, 0)
if offscreen:
if x_delta:
x1 = mouse_x - tip_delta[0] - width
if y_delta:
y1 = mouse_y - tip_delta[1] - height
offscreen_again = y1 < 0 # out on the top
if offscreen_again:
y1 = 0
return x1, y1
bg = self.bg
@ -111,21 +89,18 @@ class CanvasTooltip:
self.tw.wm_overrideredirect(True)
win = tk.Frame(self.tw, background=bg, borderwidth=0)
win.grid()
label = ttk.Label(
win,
text=self.text,
textvariable=self.text,
justify=tk.LEFT,
background=bg,
relief=tk.SOLID,
borderwidth=0,
wraplength=self.wraplength,
)
label.grid(padx=(pad[0], pad[2]), pady=(pad[1], pad[3]), sticky=tk.NSEW)
win.grid()
x, y = tip_pos_calculator(canvas, label)
self.tw.wm_geometry("+%d+%d" % (x, y))
def hide(self):

View file

@ -15,6 +15,17 @@ from coretk.wlannodeconfig import WlanNodeConfig
NETWORK_NODES = {"switch", "hub", "wlan", "rj45", "tunnel", "emane"}
DEFAULT_NODES = {"router", "host", "PC", "mdr", "prouter"}
OBSERVER_WIDGETS = {
"processes": "ps",
"ifconfig": "ifconfig",
"IPV4 Routes": "ip -4 ro",
"IPV6 Routes": "ip -6 ro",
"Listening sockets": "netstat -tuwnl",
"IPv4 MFC entries": "ip -4 mroute show",
"IPv6 MFC entries": "ip -6 mroute show",
"firewall rules": "iptables -L",
"IPSec policies": "setkey -DP",
}
class Node:
@ -85,6 +96,7 @@ class CoreClient:
self.master = app.master
self.interface_helper = None
self.services = {}
self.observer = None
# loaded configuration data
self.servers = {}
@ -92,6 +104,7 @@ class CoreClient:
self.read_config()
# data for managing the current session
self.state = None
self.nodes = {}
self.edges = {}
self.hooks = {}
@ -105,6 +118,9 @@ class CoreClient:
self.emaneconfig_management = EmaneModelNodeConfig(app)
self.emane_config = None
def set_observer(self, value):
self.observer = value
def read_config(self):
# read distributed server
for server_config in self.app.config["servers"]:
@ -124,8 +140,11 @@ class CoreClient:
def handle_events(self, event):
logging.info("event: %s", event)
if event.link_event is not None:
if event.HasField("link_event"):
self.app.canvas.wireless_draw.hangle_link_event(event.link_event)
elif event.HasField("session_event"):
if event.session_event.event <= core_pb2.SessionState.SHUTDOWN:
self.state = event.session_event.event
def handle_throughputs(self, event):
interface_throughputs = event.interface_throughputs
@ -159,7 +178,7 @@ class CoreClient:
response = self.client.get_session(self.session_id)
logging.info("joining session(%s): %s", self.session_id, response)
session = response.session
session_state = session.state
self.state = session.state
self.client.events(self.session_id, self.handle_events)
# get hooks
@ -207,11 +226,14 @@ class CoreClient:
self.app.canvas.canvas_reset_and_redraw(session)
# draw tool bar appropritate with session state
if session_state == core_pb2.SessionState.RUNTIME:
if self.is_runtime():
self.app.toolbar.runtime_frame.tkraise()
else:
self.app.toolbar.design_frame.tkraise()
def is_runtime(self):
return self.state == core_pb2.SessionState.RUNTIME
def create_new_session(self):
"""
Create a new session
@ -754,3 +776,7 @@ class CoreClient:
)
configs.append(config_proto)
return configs
def run(self, node_id):
logging.info("running node(%s) cmd: %s", node_id, self.observer)
return self.client.node_command(self.session_id, node_id, self.observer).output

View file

@ -150,7 +150,7 @@ class CanvasGraph(tk.Canvas):
node.type, node.model
)
n = CanvasNode(
node.position.x, node.position.y, image, name, self, node.id
node.position.x, node.position.y, image, name, self.master, node.id
)
self.nodes[n.id] = n
core_id_to_canvas_id[node.id] = n.id
@ -419,14 +419,7 @@ class CanvasGraph(tk.Canvas):
plot_id = self.find_all()[0]
logging.info("add node event: %s - %s", plot_id, self.selected)
if self.selected == plot_id:
node = CanvasNode(
x=x,
y=y,
image=image,
node_type=node_name,
canvas=self,
core_id=self.core.peek_id(),
)
node = CanvasNode(x, y, image, node_name, self.master, self.core.peek_id())
self.nodes[node.id] = node
self.core.add_graph_node(self.core.session_id, node.id, x, y, node_name)
return node
@ -491,10 +484,11 @@ class CanvasEdge:
class CanvasNode:
def __init__(self, x, y, image, node_type, canvas, core_id):
def __init__(self, x, y, image, node_type, app, core_id):
self.image = image
self.node_type = node_type
self.canvas = canvas
self.app = app
self.canvas = app.canvas
self.id = self.canvas.create_image(
x, y, anchor=tk.CENTER, image=self.image, tags="node"
)
@ -506,19 +500,30 @@ class CanvasNode:
x, y + 20, text=self.name, tags="nodename"
)
self.antenna_draw = WlanAntennaManager(self.canvas, self.id)
self.tooltip = CanvasTooltip(self.canvas)
self.canvas.tag_bind(self.id, "<ButtonPress-1>", self.click_press)
self.canvas.tag_bind(self.id, "<ButtonRelease-1>", self.click_release)
self.canvas.tag_bind(self.id, "<B1-Motion>", self.motion)
self.canvas.tag_bind(self.id, "<Button-3>", self.context)
self.canvas.tag_bind(self.id, "<Double-Button-1>", self.double_click)
self.canvas.tag_bind(self.id, "<Control-1>", self.select_multiple)
self.tooltip = CanvasTooltip(self.canvas, self.id, text=self.name)
self.canvas.tag_bind(self.id, "<Enter>", self.on_enter)
self.canvas.tag_bind(self.id, "<Leave>", self.on_leave)
self.edges = set()
self.wlans = []
self.moving = None
def on_enter(self, event):
if self.app.core.is_runtime() and self.app.core.observer:
self.tooltip.text.set("waiting...")
self.tooltip.on_enter(event)
output = self.app.core.run(self.core_id)
self.tooltip.text.set(output)
def on_leave(self, event):
self.tooltip.on_leave(event)
def click(self, event):
print("click")

View file

@ -1,6 +1,8 @@
import tkinter as tk
from functools import partial
import coretk.menuaction as action
from coretk.coreclient import OBSERVER_WIDGETS
class Menubar(tk.Menu):
@ -364,23 +366,26 @@ class Menubar(tk.Menu):
:param tkinter.Menu widget_menu: widget_menu
:return: nothing
"""
var = tk.StringVar(value="none")
menu = tk.Menu(widget_menu)
menu.add_command(label="None", state=tk.DISABLED)
menu.add_command(label="processes", state=tk.DISABLED)
menu.add_command(label="ifconfig", state=tk.DISABLED)
menu.add_command(label="IPv4 routes", state=tk.DISABLED)
menu.add_command(label="IPv6 routes", state=tk.DISABLED)
menu.add_command(label="OSPFv2 neighbors", state=tk.DISABLED)
menu.add_command(label="OSPFv3 neighbors", state=tk.DISABLED)
menu.add_command(label="Listening sockets", state=tk.DISABLED)
menu.add_command(label="IPv4 MFC entries", state=tk.DISABLED)
menu.add_command(label="IPv6 MFC entries", state=tk.DISABLED)
menu.add_command(label="firewall rules", state=tk.DISABLED)
menu.add_command(label="IPsec policies", state=tk.DISABLED)
menu.add_command(label="docker logs", state=tk.DISABLED)
menu.add_command(label="OSPFv3 MDR level", state=tk.DISABLED)
menu.add_command(label="PIM neighbors", state=tk.DISABLED)
menu.add_command(label="Edit...", command=self.menuaction.edit_observer_widgets)
menu.var = var
menu.add_radiobutton(
label="None",
variable=var,
value="none",
command=lambda: self.app.core.set_observer(None),
)
for name in sorted(OBSERVER_WIDGETS):
cmd = OBSERVER_WIDGETS[name]
menu.add_radiobutton(
label=name,
variable=var,
value=name,
command=partial(self.app.core.set_observer, cmd),
)
menu.add_radiobutton(
label="Edit...", command=self.menuaction.edit_observer_widgets
)
widget_menu.add_cascade(label="Observer Widgets", menu=menu)
def create_adjacency_menu(self, widget_menu):

View file

@ -184,9 +184,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
logging.debug("stop session: %s", request)
session = self.get_session(request.session_id, context)
session.data_collect()
session.set_state(EventTypes.DATACOLLECT_STATE)
session.set_state(EventTypes.DATACOLLECT_STATE, send_event=True)
session.clear()
session.set_state(EventTypes.SHUTDOWN_STATE)
session.set_state(EventTypes.SHUTDOWN_STATE, send_event=True)
return core_pb2.StopSessionResponse(result=True)
def CreateSession(self, request, context):