Merge branch 'coretk' into coretk-config

This commit is contained in:
Huy Pham 2019-11-21 07:39:35 -08:00
commit 56876710a1
7 changed files with 92 additions and 294 deletions

View file

@ -1,45 +0,0 @@
"""
canvas graph action
"""
from core.api.grpc import core_pb2
from coretk.dialogs.emaneconfig import EmaneConfiguration
from coretk.dialogs.nodeconfig import NodeConfigDialog
from coretk.dialogs.wlanconfig import WlanConfigDialog
from coretk.nodeutils import NodeUtils
class CanvasAction:
def __init__(self, master, canvas):
self.master = master
self.canvas = canvas
self.node_to_show_config = None
def display_configuration(self, canvas_node):
node_type = canvas_node.core_node.type
self.node_to_show_config = canvas_node
if NodeUtils.is_container_node(node_type):
self.display_node_configuration()
elif node_type == core_pb2.NodeType.WIRELESS_LAN:
self.display_wlan_configuration(canvas_node)
elif node_type == core_pb2.NodeType.EMANE:
self.display_emane_configuration()
def display_node_configuration(self):
dialog = NodeConfigDialog(self.master, self.master, self.node_to_show_config)
dialog.show()
self.node_to_show_config = None
def display_wlan_configuration(self, canvas_node):
wlan_config = self.master.core.wlanconfig_management.configurations[
canvas_node.core_node.id
]
dialog = WlanConfigDialog(
self.master, self.master, self.node_to_show_config, wlan_config
)
dialog.show()
self.node_to_show_config = None
def display_emane_configuration(self):
app = self.canvas.core.app
dialog = EmaneConfiguration(self.master, app, self.node_to_show_config)
dialog.show()

View file

@ -12,7 +12,6 @@ from coretk.mobilitynodeconfig import MobilityNodeConfig
from coretk.nodeutils import NodeDraw, NodeUtils
from coretk.servicefileconfig import ServiceFileConfig
from coretk.servicenodeconfig import ServiceNodeConfig
from coretk.wlannodeconfig import WlanNodeConfig
OBSERVERS = {
"processes": "ps",
@ -70,7 +69,7 @@ class CoreClient:
self.reusable = []
self.preexisting = set()
self.interfaces_manager = InterfaceManager()
self.wlanconfig_management = WlanNodeConfig()
self.wlan_configs = {}
self.mobilityconfig_management = MobilityNodeConfig()
self.emaneconfig_management = EmaneModelNodeConfig(app)
self.emane_config = None
@ -136,7 +135,7 @@ class CoreClient:
self.canvas_nodes.clear()
self.links.clear()
self.hooks.clear()
self.wlanconfig_management.configurations.clear()
self.wlan_configs.clear()
self.mobilityconfig_management.configurations.clear()
self.emane_config = None
@ -158,9 +157,7 @@ class CoreClient:
if node.type == core_pb2.NodeType.WIRELESS_LAN:
response = self.client.get_wlan_config(self.session_id, node.id)
logging.debug("wlan config(%s): %s", node.id, response)
node_config = response.config
config = {x: node_config[x].value for x in node_config}
self.wlanconfig_management.configurations[node.id] = config
self.wlan_configs[node.id] = response.config
# get mobility configs
response = self.client.get_mobility_configs(self.session_id)
@ -458,7 +455,6 @@ class CoreClient:
)
# set default configuration for wireless node
self.wlanconfig_management.set_default_config(node_type, node_id)
self.mobilityconfig_management.set_default_configuration(node_type, node_id)
# set default emane configuration for emane node
@ -525,8 +521,8 @@ class CoreClient:
for i in node_ids:
if i in self.mobilityconfig_management.configurations:
self.mobilityconfig_management.configurations.pop(i)
if i in self.wlanconfig_management.configurations:
self.wlanconfig_management.configurations.pop(i)
if i in self.wlan_configs:
del self.wlan_configs[i]
# delete emane configurations
for i in node_interface_pairs:
@ -611,11 +607,10 @@ class CoreClient:
def get_wlan_configs_proto(self):
configs = []
wlan_configs = self.wlanconfig_management.configurations
for node_id in wlan_configs:
config = wlan_configs[node_id]
config_proto = core_pb2.WlanConfig(node_id=node_id, config=config)
configs.append(config_proto)
for node_id, config in self.wlan_configs.items():
config = {x: config[x].value for x in config}
wlan_config = core_pb2.WlanConfig(node_id=node_id, config=config)
configs.append(wlan_config)
return configs
def get_mobility_configs_proto(self):
@ -675,3 +670,11 @@ class CoreClient:
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
def get_wlan_config(self, node_id):
config = self.wlan_configs.get(node_id)
if not config:
response = self.client.get_wlan_config(self.session_id, node_id)
config = response.config
self.wlan_configs[node_id] = config
return config

View file

@ -107,8 +107,8 @@ class NodeConfigDialog(Dialog):
entry.grid(row=row, column=1, sticky="ew")
row += 1
# server
if NodeUtils.is_container_node(self.node.type):
# server
frame.grid(sticky="ew")
frame.columnconfigure(1, weight=1)
label = ttk.Label(frame, text="Server")
@ -121,9 +121,9 @@ class NodeConfigDialog(Dialog):
combobox.grid(row=row, column=1, sticky="ew")
row += 1
# services
button = ttk.Button(self.top, text="Services", command=self.click_services)
button.grid(sticky="ew", pady=PAD)
# services
button = ttk.Button(self.top, text="Services", command=self.click_services)
button.grid(sticky="ew", pady=PAD)
# interfaces
if self.canvas_node.interfaces:

View file

@ -2,152 +2,33 @@
wlan configuration
"""
import tkinter as tk
from tkinter import ttk
from coretk.dialogs.dialog import Dialog
from coretk.dialogs.icondialog import IconDialog
from coretk.dialogs.mobilityconfig import MobilityConfigDialog
from coretk.widgets import ConfigFrame
PAD = 5
class WlanConfigDialog(Dialog):
def __init__(self, master, app, canvas_node, config):
def __init__(self, master, app, canvas_node):
super().__init__(
master, app, f"{canvas_node.core_node.name} Wlan Configuration", modal=True
)
self.image = canvas_node.image
self.canvas_node = canvas_node
self.node = canvas_node.core_node
self.config = config
self.name = tk.StringVar(value=self.node.name)
self.range_var = tk.StringVar(value=config["range"])
self.bandwidth_var = tk.StringVar(value=config["bandwidth"])
self.delay_var = tk.StringVar(value=config["delay"])
self.loss_var = tk.StringVar(value=config["error"])
self.jitter_var = tk.StringVar(value=config["jitter"])
self.ip4_subnet = tk.StringVar()
self.ip6_subnet = tk.StringVar()
self.image_button = None
self.config_frame = None
self.config = self.app.core.get_wlan_config(self.node.id)
self.draw()
def draw(self):
self.top.columnconfigure(0, weight=1)
self.draw_name_config()
self.draw_wlan_config()
self.draw_subnet()
self.draw_wlan_buttons()
self.config_frame = ConfigFrame(self.top, self.app, self.config, borderwidth=0)
self.config_frame.draw_config()
self.config_frame.grid(sticky="nsew", pady=PAD)
self.draw_apply_buttons()
def draw_name_config(self):
"""
draw image modification part
:return: nothing
"""
frame = ttk.Frame(self.top)
frame.grid(pady=2, sticky="ew")
frame.columnconfigure(0, weight=1)
entry = ttk.Entry(frame, textvariable=self.name)
entry.grid(row=0, column=0, padx=2, sticky="ew")
self.image_button = ttk.Button(frame, image=self.image, command=self.click_icon)
self.image_button.grid(row=0, column=1, padx=3)
def draw_wlan_config(self):
"""
create wireless configuration table
:return: nothing
"""
label = ttk.Label(self.top, text="Wireless")
label.grid(sticky="w", pady=2)
frame = ttk.Frame(self.top)
frame.grid(pady=2, sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
label = ttk.Label(
frame,
text=(
"The basic range model calculates on/off "
"connectivity based on pixel distance between nodes."
),
)
label.grid(row=0, columnspan=2, pady=2, sticky="ew")
label = ttk.Label(frame, text="Range")
label.grid(row=1, column=0, sticky="w")
entry = ttk.Entry(frame, textvariable=self.range_var)
entry.grid(row=1, column=1, sticky="ew")
label = ttk.Label(frame, text="Bandwidth (bps)")
label.grid(row=2, column=0, sticky="w")
entry = ttk.Entry(frame, textvariable=self.bandwidth_var)
entry.grid(row=2, column=1, sticky="ew")
label = ttk.Label(frame, text="Delay (us)")
label.grid(row=3, column=0, sticky="w")
entry = ttk.Entry(frame, textvariable=self.delay_var)
entry.grid(row=3, column=1, sticky="ew")
label = ttk.Label(frame, text="Loss (%)")
label.grid(row=4, column=0, sticky="w")
entry = ttk.Entry(frame, textvariable=self.loss_var)
entry.grid(row=4, column=1, sticky="ew")
label = ttk.Label(frame, text="Jitter (us)")
label.grid(row=5, column=0, sticky="w")
entry = ttk.Entry(frame, textvariable=self.jitter_var)
entry.grid(row=5, column=1, sticky="ew")
def draw_subnet(self):
"""
create the entries for ipv4 subnet and ipv6 subnet
:return: nothing
"""
frame = ttk.Frame(self.top)
frame.grid(pady=3, sticky="ew")
frame.columnconfigure(1, weight=1)
frame.columnconfigure(3, weight=1)
label = ttk.Label(frame, text="IPv4 Subnet")
label.grid(row=0, column=0, sticky="w")
entry = ttk.Entry(frame, textvariable=self.ip4_subnet)
entry.grid(row=0, column=1, sticky="ew")
label = ttk.Label(frame, text="IPv6 Subnet")
label.grid(row=0, column=2, sticky="w")
entry = ttk.Entry(frame, textvariable=self.ip6_subnet)
entry.grid(row=0, column=3, sticky="ew")
def draw_wlan_buttons(self):
"""
create wireless node options
:return:
"""
frame = ttk.Frame(self.top)
frame.grid(pady=2, sticky="ew")
for i in range(3):
frame.columnconfigure(i, weight=1)
button = ttk.Button(
frame, text="ns-2 mobility script...", command=self.click_mobility
)
button.grid(row=0, column=0, padx=2, sticky="ew")
button = ttk.Button(frame, text="Link to all routers")
button.grid(row=0, column=1, padx=2, sticky="ew")
button = ttk.Button(frame, text="Choose WLAN members")
button.grid(row=0, column=2, padx=2, sticky="ew")
def draw_apply_buttons(self):
"""
create node configuration options
@ -160,42 +41,21 @@ class WlanConfigDialog(Dialog):
frame.columnconfigure(i, weight=1)
button = ttk.Button(frame, text="Apply", command=self.click_apply)
button.grid(row=0, column=0, padx=2, sticky="ew")
button.grid(row=0, column=0, padx=PAD, sticky="ew")
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, padx=2, sticky="ew")
button.grid(row=0, column=1, sticky="ew")
def click_mobility(self):
dialog = MobilityConfigDialog(self, self.app, self.canvas_node)
dialog.show()
def click_icon(self):
dialog = IconDialog(self, self.app, self.node.name, self.canvas_node.image)
dialog.show()
if dialog.image:
self.image = dialog.image
self.image_button.config(image=self.image)
def click_apply(self):
"""
retrieve user's wlan configuration and store the new configuration values
:return: nothing
"""
basic_range = self.range_var.get()
bandwidth = self.bandwidth_var.get()
delay = self.delay_var.get()
loss = self.loss_var.get()
jitter = self.jitter_var.get()
# set wireless node configuration here
wlanconfig_manager = self.app.core.wlanconfig_management
wlanconfig_manager.set_custom_config(
node_id=self.node.id,
range=basic_range,
bandwidth=bandwidth,
jitter=jitter,
delay=delay,
error=loss,
)
self.config_frame.parse_config()
self.app.core.wlan_configs[self.node.id] = self.config
self.destroy()

View file

@ -5,8 +5,11 @@ import tkinter as tk
from PIL import ImageTk
from core.api.grpc import core_pb2
from coretk.canvasaction import CanvasAction
from core.api.grpc.core_pb2 import NodeType
from coretk.canvastooltip import CanvasTooltip
from coretk.dialogs.mobilityconfig import MobilityConfigDialog
from coretk.dialogs.nodeconfig import NodeConfigDialog
from coretk.dialogs.wlanconfig import WlanConfigDialog
from coretk.graph_helper import GraphHelper, WlanAntennaManager
from coretk.images import Images
from coretk.linkinfo import LinkInfo, Throughput
@ -38,24 +41,21 @@ class CanvasGraph(tk.Canvas):
kwargs["highlightthickness"] = 0
super().__init__(master, cnf, **kwargs)
self.mode = GraphMode.SELECT
self.node_draw = None
self.selected = None
self.node_context = None
self.node_draw = None
self.context = None
self.nodes = {}
self.edges = {}
self.drawing_edge = None
self.grid = None
self.meters_per_pixel = 1.5
self.canvas_management = CanvasComponentManagement(self, core)
self.canvas_action = CanvasAction(master, self)
self.setup_menus()
self.setup_bindings()
self.draw_grid()
self.core = core
self.helper = GraphHelper(self, core)
self.throughput_draw = Throughput(self, core)
self.wireless_draw = WirelessConnection(self, core)
self.is_node_context_opened = False
# background related
self.wallpaper_id = None
@ -66,21 +66,28 @@ class CanvasGraph(tk.Canvas):
self.show_grid = tk.BooleanVar(value=True)
self.adjust_to_dim = tk.BooleanVar(value=False)
def setup_menus(self):
self.node_context = tk.Menu(self.master)
self.node_context.add_command(
label="Configure", command=self.canvas_action.display_node_configuration
)
self.node_context.add_command(label="Select adjacent")
self.node_context.add_command(label="Create link to")
self.node_context.add_command(label="Assign to")
self.node_context.add_command(label="Move to")
self.node_context.add_command(label="Cut")
self.node_context.add_command(label="Copy")
self.node_context.add_command(label="Paste")
self.node_context.add_command(label="Delete")
self.node_context.add_command(label="Hide")
self.node_context.add_command(label="Services")
def create_node_context(self, canvas_node):
node = canvas_node.core_node
context = tk.Menu(self.master)
context.add_command(label="Configure", command=canvas_node.show_config)
if node.type == NodeType.WIRELESS_LAN:
context.add_command(
label="WLAN Config", command=canvas_node.show_wlan_config
)
context.add_command(
label="Mobility Config", command=canvas_node.show_mobility_config
)
context.add_command(label="Select adjacent", state=tk.DISABLED)
context.add_command(label="Create link to", state=tk.DISABLED)
context.add_command(label="Assign to", state=tk.DISABLED)
context.add_command(label="Move to", state=tk.DISABLED)
context.add_command(label="Cut", state=tk.DISABLED)
context.add_command(label="Copy", state=tk.DISABLED)
context.add_command(label="Paste", state=tk.DISABLED)
context.add_command(label="Delete", state=tk.DISABLED)
context.add_command(label="Hide", state=tk.DISABLED)
context.add_command(label="Services", state=tk.DISABLED)
return context
def reset_and_redraw(self, session):
"""
@ -97,7 +104,6 @@ class CanvasGraph(tk.Canvas):
self.mode = GraphMode.SELECT
self.node_draw = None
self.selected = None
self.node_context = None
self.nodes.clear()
self.edges.clear()
self.drawing_edge = None
@ -112,7 +118,7 @@ class CanvasGraph(tk.Canvas):
self.bind("<ButtonPress-1>", self.click_press)
self.bind("<ButtonRelease-1>", self.click_release)
self.bind("<B1-Motion>", self.click_motion)
self.bind("<Button-3>", self.context)
self.bind("<Button-3>", self.click_context)
self.bind("<Delete>", self.press_delete)
def draw_grid(self, width=1000, height=800):
@ -254,9 +260,9 @@ class CanvasGraph(tk.Canvas):
:param event: mouse event
:return: nothing
"""
if self.is_node_context_opened:
self.node_context.unpost()
self.is_node_context_opened = False
if self.context:
self.context.unpost()
self.context = None
else:
self.focus_set()
self.selected = self.get_selected(event)
@ -350,18 +356,18 @@ class CanvasGraph(tk.Canvas):
x1, y1, _, _ = self.coords(self.drawing_edge.id)
self.coords(self.drawing_edge.id, x1, y1, x2, y2)
def context(self, event):
if not self.is_node_context_opened:
def click_context(self, event):
logging.info("context event: %s", self.context)
if not self.context:
selected = self.get_selected(event)
nodes = self.find_withtag("node")
if selected in nodes:
canvas_node = self.nodes.get(selected)
if canvas_node:
logging.debug(f"node context: {selected}")
self.node_context.post(event.x_root, event.y_root)
self.canvas_action.node_to_show_config = self.nodes[selected]
self.is_node_context_opened = True
self.context = self.create_node_context(canvas_node)
self.context.post(event.x_root, event.y_root)
else:
self.node_context.unpost()
self.is_node_context_opened = False
self.context.unpost()
self.context = None
# TODO rather than delete, might move the data to somewhere else in order to reuse
# TODO when the user undo
@ -443,7 +449,6 @@ class CanvasGraph(tk.Canvas):
"""
place the image at the center of canvas
:param Image img: image object
:return: nothing
"""
tk_img = ImageTk.PhotoImage(self.wallpaper)
@ -609,7 +614,6 @@ class CanvasNode:
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.canvas.tag_bind(self.id, "<Enter>", self.on_enter)
@ -641,7 +645,7 @@ class CanvasNode:
if self.app.core.is_runtime():
self.canvas.core.launch_terminal(self.core_node.id)
else:
self.canvas.canvas_action.display_configuration(self)
self.show_config()
def update_coords(self):
x, y = self.canvas.coords(self.id)
@ -693,5 +697,17 @@ class CanvasNode:
def select_multiple(self, event):
self.canvas.canvas_management.node_select(self, True)
def context(self, event):
logging.debug(f"context click {self.core_node.name}: {event}")
def show_config(self):
self.canvas.context = None
dialog = NodeConfigDialog(self.app, self.app, self)
dialog.show()
def show_wlan_config(self):
self.canvas.context = None
dialog = WlanConfigDialog(self.app, self.app, self)
dialog.show()
def show_mobility_config(self):
self.canvas.context = None
dialog = MobilityConfigDialog(self.app, self.app, self)
dialog.show()

View file

@ -15,6 +15,7 @@ INT_TYPES = {
core_pb2.ConfigOptionType.INT32,
core_pb2.ConfigOptionType.INT64,
}
PAD = 5
class FrameScroll(ttk.LabelFrame):
@ -72,7 +73,7 @@ class ConfigFrame(FrameScroll):
for group_name in sorted(group_mapping):
group = group_mapping[group_name]
frame = ttk.Frame(self.frame)
frame = ttk.Frame(self.frame, padding=PAD)
frame.columnconfigure(1, weight=1)
self.frame.add(frame, text=group_name)
for index, option in enumerate(sorted(group, key=lambda x: x.name)):

View file

@ -1,37 +0,0 @@
"""
wireless node configuration for all the wireless node
"""
from collections import OrderedDict
from core.api.grpc import core_pb2
class WlanNodeConfig:
def __init__(self):
# maps node id to wlan configuration
self.configurations = {}
def set_default_config(self, node_type, node_id):
if node_type == core_pb2.NodeType.WIRELESS_LAN:
config = OrderedDict()
config["range"] = "275"
config["bandwidth"] = "54000000"
config["jitter"] = "0"
config["delay"] = "20000"
config["error"] = "0"
self.configurations[node_id] = config
def set_custom_config(self, node_id, range, bandwidth, jitter, delay, error):
self.configurations[node_id]["range"] = range
self.configurations[node_id]["bandwidth"] = bandwidth
self.configurations[node_id]["jitter"] = jitter
self.configurations[node_id]["delay"] = delay
self.configurations[node_id]["error"] = error
def delete_node_config(self, node_id):
"""
not implemented
:param node_id:
:return:
"""
return