Merge branch 'coretk' into coretk-config

This commit is contained in:
Huy Pham 2019-11-20 16:53:05 -08:00
commit 37c032afc5
9 changed files with 181 additions and 73 deletions

View file

@ -5,6 +5,7 @@ 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:
@ -16,7 +17,7 @@ class CanvasAction:
def display_configuration(self, canvas_node):
node_type = canvas_node.core_node.type
self.node_to_show_config = canvas_node
if node_type == core_pb2.NodeType.DEFAULT:
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)
@ -30,7 +31,7 @@ class CanvasAction:
def display_wlan_configuration(self, canvas_node):
wlan_config = self.master.core.wlanconfig_management.configurations[
canvas_node.core_id
canvas_node.core_node.id
]
dialog = WlanConfigDialog(
self.master, self.master, self.node_to_show_config, wlan_config

View file

@ -445,12 +445,16 @@ class CoreClient:
"""
node_id = self.get_id()
position = core_pb2.Position(x=x, y=y)
image = None
if NodeUtils.is_image_node(node_type):
image = "ubuntu:latest"
node = core_pb2.Node(
id=node_id,
type=node_type,
name=f"n{node_id}",
model=model,
position=position,
image=image,
)
# set default configuration for wireless node
@ -535,7 +539,7 @@ class CoreClient:
def create_interface(self, canvas_node):
interface = None
core_node = canvas_node.core_node
if NodeUtils.is_interface_node(core_node.type):
if NodeUtils.is_container_node(core_node.type):
ifid = len(canvas_node.interfaces)
name = f"eth{ifid}"
interface = core_pb2.Interface(

View file

@ -20,6 +20,7 @@ class EmaneConfiguration(Dialog):
super().__init__(master, app, "emane configuration", modal=False)
self.app = app
self.canvas_node = canvas_node
self.node = canvas_node.core_node
self.radiovar = tk.IntVar()
self.radiovar.set(1)
self.columnconfigure(0, weight=1)
@ -122,20 +123,15 @@ class EmaneConfiguration(Dialog):
# add string emane_ infront for grpc call
response = self.app.core.client.set_emane_model_config(
self.app.core.session_id,
self.canvas_node.core_id,
"emane_" + model_name,
config,
self.app.core.session_id, self.node.id, f"emane_{model_name}", config
)
logging.info(
"emaneconfig.py config emane model (%s), result: %s",
self.canvas_node.core_id,
response,
"emaneconfig.py config emane model (%s), result: %s", self.node.id, response
)
# store the change locally
self.app.core.emaneconfig_management.set_custom_emane_cloud_config(
self.canvas_node.core_id, "emane_" + model_name
self.node.id, f"emane_{model_name}"
)
self.emane_model_dialog.destroy()
@ -161,7 +157,7 @@ class EmaneConfiguration(Dialog):
session_id = self.app.core.session_id
# add string emane_ before model name for grpc call
response = self.app.core.client.get_emane_model_config(
session_id, self.canvas_node.core_id, "emane_" + model_name
session_id, self.node.id, f"emane_{model_name}"
)
logging.info("emane model config %s", response)

View file

@ -19,9 +19,10 @@ class MobilityConfigDialog(Dialog):
"""
super().__init__(master, app, "ns2script configuration", modal=True)
self.canvas_node = canvas_node
self.node = canvas_node.core_node
logging.info(app.canvas.core.mobilityconfig_management.configurations)
self.node_config = app.canvas.core.mobilityconfig_management.configurations[
canvas_node.core_id
self.node.id
]
self.mobility_script_parameters()
@ -208,7 +209,7 @@ class MobilityConfigDialog(Dialog):
else:
loop = "0"
self.app.canvas.core.mobilityconfig_management.set_custom_configuration(
node_id=self.canvas_node.core_id,
node_id=self.node.id,
file=file,
refresh_ms=refresh_time,
loop=loop,

View file

@ -1,14 +1,36 @@
import logging
import tkinter as tk
from functools import partial
from tkinter import ttk
from coretk.dialogs.dialog import Dialog
from coretk.dialogs.icondialog import IconDialog
from coretk.dialogs.nodeservice import NodeService
from coretk.nodeutils import NodeUtils
from coretk.widgets import FrameScroll
DEFAULT_NODES = {"router", "host", "PC", "mdr", "prouter"}
PAD = 5
def mac_auto(is_auto, entry):
logging.info("mac auto clicked")
if is_auto.get():
logging.info("disabling mac")
entry.var.set("")
entry.config(state=tk.DISABLED)
else:
entry.var.set("00:00:00:00:00:00")
entry.config(state=tk.NORMAL)
class InterfaceData:
def __init__(self, is_auto, mac, ip4, ip6):
self.is_auto = is_auto
self.mac = mac
self.ip4 = ip4
self.ip6 = ip6
class NodeConfigDialog(Dialog):
def __init__(self, master, app, canvas_node):
"""
@ -18,13 +40,21 @@ class NodeConfigDialog(Dialog):
:param coretk.app.Application: main app
:param coretk.graph.CanvasNode canvas_node: canvas node object
"""
super().__init__(master, app, f"{canvas_node.name} Configuration", modal=True)
super().__init__(
master, app, f"{canvas_node.core_node.name} Configuration", modal=True
)
self.canvas_node = canvas_node
self.node = canvas_node.core_node
self.image = canvas_node.image
self.image_button = None
self.name = tk.StringVar(value=canvas_node.name)
self.type = tk.StringVar(value=canvas_node.core_node.model)
self.server = tk.StringVar()
self.name = tk.StringVar(value=self.node.name)
self.type = tk.StringVar(value=self.node.model)
self.container_image = tk.StringVar(value=self.node.image)
server = "localhost"
if self.node.server:
server = self.node.server
self.server = tk.StringVar(value=server)
self.interfaces = {}
self.draw()
def draw(self):
@ -57,15 +87,28 @@ class NodeConfigDialog(Dialog):
row += 1
# node type field
if NodeUtils.is_model_node(self.node.type):
label = ttk.Label(frame, text="Type")
label.grid(row=row, column=0, sticky="ew", padx=PAD, pady=PAD)
combobox = ttk.Combobox(
frame, textvariable=self.type, values=list(DEFAULT_NODES), state="readonly"
frame,
textvariable=self.type,
values=list(NodeUtils.NODE_MODELS),
state="readonly",
)
combobox.grid(row=row, column=1, sticky="ew")
row += 1
# container image field
if NodeUtils.is_image_node(self.node.type):
label = ttk.Label(frame, text="Image")
label.grid(row=row, column=0, sticky="ew", padx=PAD, pady=PAD)
entry = ttk.Entry(frame, textvariable=self.container_image)
entry.grid(row=row, column=1, sticky="ew")
row += 1
# server
if NodeUtils.is_container_node(self.node.type):
frame.grid(sticky="ew")
frame.columnconfigure(1, weight=1)
label = ttk.Label(frame, text="Server")
@ -82,8 +125,50 @@ class NodeConfigDialog(Dialog):
button = ttk.Button(self.top, text="Services", command=self.click_services)
button.grid(sticky="ew", pady=PAD)
# interfaces
if self.canvas_node.interfaces:
self.draw_interfaces()
self.draw_buttons()
def draw_interfaces(self):
scroll = FrameScroll(self.top, self.app, text="Interfaces")
scroll.grid(sticky="nsew")
scroll.frame.columnconfigure(0, weight=1)
scroll.frame.rowconfigure(0, weight=1)
for interface in self.canvas_node.interfaces:
logging.info("interface: %s", interface)
frame = ttk.LabelFrame(scroll.frame, text=interface.name, padding=PAD)
frame.grid(sticky="ew", pady=PAD)
frame.columnconfigure(1, weight=1)
frame.columnconfigure(2, weight=1)
label = ttk.Label(frame, text="MAC")
label.grid(row=0, column=0, padx=PAD, pady=PAD)
is_auto = tk.BooleanVar(value=True)
checkbutton = ttk.Checkbutton(frame, text="Auto?", variable=is_auto)
checkbutton.var = is_auto
checkbutton.grid(row=0, column=1, padx=PAD)
mac = tk.StringVar(value=interface.mac)
entry = ttk.Entry(frame, textvariable=mac, state=tk.DISABLED)
entry.grid(row=0, column=2, sticky="ew")
func = partial(mac_auto, is_auto, entry)
checkbutton.config(command=func)
label = ttk.Label(frame, text="IPv4")
label.grid(row=1, column=0, padx=PAD, pady=PAD)
ip4 = tk.StringVar(value=f"{interface.ip4}/{interface.ip4mask}")
entry = ttk.Entry(frame, textvariable=ip4)
entry.grid(row=1, column=1, columnspan=2, sticky="ew")
label = ttk.Label(frame, text="IPv6")
label.grid(row=2, column=0, padx=PAD, pady=PAD)
ip6 = tk.StringVar(value=f"{interface.ip6}/{interface.ip6mask}")
entry = ttk.Entry(frame, textvariable=ip6)
entry.grid(row=2, column=1, columnspan=2, sticky="ew")
self.interfaces[interface.id] = InterfaceData(is_auto, mac, ip4, ip6)
def draw_buttons(self):
frame = ttk.Frame(self.top)
frame.grid(sticky="ew")
@ -101,16 +186,24 @@ class NodeConfigDialog(Dialog):
dialog.show()
def click_icon(self):
dialog = IconDialog(
self, self.app, self.canvas_node.name, self.canvas_node.image
)
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 config_apply(self):
self.canvas_node.name = self.name.get()
# update core node
self.node.name = self.name.get()
if NodeUtils.is_image_node(self.node.type):
self.node.image = self.container_image.get()
if NodeUtils.is_container_node(self.node.type):
self.node.server = self.server.get()
# update canvas node
self.canvas_node.image = self.image
self.canvas_node.canvas.itemconfig(self.canvas_node.id, image=self.image)
# redraw
self.canvas_node.redraw()
self.destroy()

View file

@ -13,13 +13,14 @@ from coretk.dialogs.mobilityconfig import MobilityConfigDialog
class WlanConfigDialog(Dialog):
def __init__(self, master, app, canvas_node, config):
super().__init__(
master, app, f"{canvas_node.name} Wlan Configuration", modal=True
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=canvas_node.name)
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"])
@ -169,9 +170,7 @@ class WlanConfigDialog(Dialog):
dialog.show()
def click_icon(self):
dialog = IconDialog(
self, self.app, self.canvas_node.name, self.canvas_node.image
)
dialog = IconDialog(self, self.app, self.node.name, self.canvas_node.image)
dialog.show()
if dialog.image:
self.image = dialog.image
@ -192,7 +191,7 @@ class WlanConfigDialog(Dialog):
# set wireless node configuration here
wlanconfig_manager = self.app.core.wlanconfig_management
wlanconfig_manager.set_custom_config(
node_id=self.canvas_node.core_id,
node_id=self.node.id,
range=basic_range,
bandwidth=bandwidth,
jitter=jitter,

View file

@ -155,21 +155,22 @@ class CanvasGraph(tk.Canvas):
# draw nodes on the canvas
image = NodeUtils.node_icon(core_node.type, core_node.model)
position = core_node.position
node = CanvasNode(position.x, position.y, image, self.master, core_node)
node = CanvasNode(self.master, core_node, image)
self.nodes[node.id] = node
self.core.canvas_nodes[core_node.id] = node
# draw existing links
for link in session.links:
canvas_node_one = self.core.canvas_nodes[link.node_one_id]
node_one = canvas_node_one.core_node
canvas_node_two = self.core.canvas_nodes[link.node_two_id]
node_two = canvas_node_two.core_node
is_wired = link.type == core_pb2.LinkType.WIRED
edge = CanvasEdge(
canvas_node_one.x_coord,
canvas_node_one.y_coord,
canvas_node_two.x_coord,
canvas_node_two.y_coord,
node_one.position.x,
node_one.position.y,
node_two.position.x,
node_two.position.y,
canvas_node_one.id,
self,
is_wired=is_wired,
@ -402,7 +403,7 @@ class CanvasGraph(tk.Canvas):
core_node = self.core.create_node(
int(x), int(y), self.node_draw.node_type, self.node_draw.model
)
node = CanvasNode(x, y, self.node_draw.image, self.master, core_node)
node = CanvasNode(self.master, core_node, self.node_draw.image)
self.core.canvas_nodes[core_node.id] = node
self.nodes[node.id] = node
return node
@ -590,19 +591,18 @@ class CanvasEdge:
class CanvasNode:
def __init__(self, x, y, image, app, core_node):
self.image = image
def __init__(self, app, core_node, image):
self.app = app
self.canvas = app.canvas
self.image = image
self.core_node = core_node
x = self.core_node.position.x
y = self.core_node.position.y
self.id = self.canvas.create_image(
x, y, anchor=tk.CENTER, image=self.image, tags="node"
)
self.core_node = core_node
self.name = core_node.name
self.x_coord = x
self.y_coord = y
self.text_id = self.canvas.create_text(
x, y + 20, text=self.name, tags="nodename"
x, y + 20, text=self.core_node.name, tags="nodename"
)
self.antenna_draw = WlanAntennaManager(self.canvas, self.id)
self.tooltip = CanvasTooltip(self.canvas)
@ -620,6 +620,10 @@ class CanvasNode:
self.wlans = []
self.moving = None
def redraw(self):
self.canvas.itemconfig(self.id, image=self.image)
self.canvas.itemconfig(self.text_id, text=self.core_node.name)
def on_enter(self, event):
if self.app.core.is_runtime() and self.app.core.observer:
self.tooltip.text.set("waiting...")
@ -640,18 +644,18 @@ class CanvasNode:
self.canvas.canvas_action.display_configuration(self)
def update_coords(self):
self.x_coord, self.y_coord = self.canvas.coords(self.id)
self.core_node.position.x = int(self.x_coord)
self.core_node.position.y = int(self.y_coord)
x, y = self.canvas.coords(self.id)
self.core_node.position.x = int(x)
self.core_node.position.y = int(y)
def click_press(self, event):
logging.debug(f"node click press {self.name}: {event}")
logging.debug(f"node click press {self.core_node.name}: {event}")
self.moving = self.canvas.canvas_xy(event)
self.canvas.canvas_management.node_select(self)
def click_release(self, event):
logging.debug(f"node click release {self.name}: {event}")
logging.debug(f"node click release {self.core_node.name}: {event}")
self.update_coords()
self.moving = None
@ -681,7 +685,6 @@ class CanvasNode:
else:
self.canvas.coords(edge.id, x1, y1, new_x, new_y)
edge.link_info.recalculate_info()
# self.canvas.core_grpc.throughput_draw.update_throughtput_location(edge)
self.canvas.helper.update_wlan_connection(
old_x, old_y, new_x, new_y, self.wlans
@ -691,4 +694,4 @@ class CanvasNode:
self.canvas.canvas_management.node_select(self, True)
def context(self, event):
logging.debug(f"context click {self.name}: {event}")
logging.debug(f"context click {self.core_node.name}: {event}")

View file

@ -44,11 +44,21 @@ class NodeUtils:
NODES = []
NETWORK_NODES = []
NODE_ICONS = {}
INTERFACE_NODE = {NodeType.DEFAULT, NodeType.DOCKER, NodeType.LXC}
CONTAINER_NODES = {NodeType.DEFAULT, NodeType.DOCKER, NodeType.LXC}
IMAGE_NODES = {NodeType.DOCKER, NodeType.LXC}
NODE_MODELS = {"router", "host", "PC", "mdr", "prouter"}
@classmethod
def is_interface_node(cls, node_type):
return node_type in cls.INTERFACE_NODE
def is_container_node(cls, node_type):
return node_type in cls.CONTAINER_NODES
@classmethod
def is_model_node(cls, node_type):
return node_type == NodeType.DEFAULT
@classmethod
def is_image_node(cls, node_type):
return node_type in cls.IMAGE_NODES
@classmethod
def node_icon(cls, node_type, model):

View file

@ -85,7 +85,8 @@ def load(style):
"fieldbackground": Colors.white,
"foreground": Colors.black,
"padding": (2, 0),
}
},
"map": {"fieldbackground": [("disabled", Colors.frame)]},
},
"TCombobox": {
"configure": {