Merge branch 'coretk' into coretk-config
This commit is contained in:
commit
37c032afc5
9 changed files with 181 additions and 73 deletions
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,33 +87,88 @@ class NodeConfigDialog(Dialog):
|
|||
row += 1
|
||||
|
||||
# node type field
|
||||
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"
|
||||
)
|
||||
combobox.grid(row=row, column=1, sticky="ew")
|
||||
row += 1
|
||||
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(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
|
||||
frame.grid(sticky="ew")
|
||||
frame.columnconfigure(1, weight=1)
|
||||
label = ttk.Label(frame, text="Server")
|
||||
label.grid(row=row, column=0, sticky="ew", padx=PAD, pady=PAD)
|
||||
servers = ["localhost"]
|
||||
servers.extend(list(sorted(self.app.core.servers.keys())))
|
||||
combobox = ttk.Combobox(
|
||||
frame, textvariable=self.server, values=servers, state="readonly"
|
||||
)
|
||||
combobox.grid(row=row, column=1, sticky="ew")
|
||||
row += 1
|
||||
if NodeUtils.is_container_node(self.node.type):
|
||||
frame.grid(sticky="ew")
|
||||
frame.columnconfigure(1, weight=1)
|
||||
label = ttk.Label(frame, text="Server")
|
||||
label.grid(row=row, column=0, sticky="ew", padx=PAD, pady=PAD)
|
||||
servers = ["localhost"]
|
||||
servers.extend(list(sorted(self.app.core.servers.keys())))
|
||||
combobox = ttk.Combobox(
|
||||
frame, textvariable=self.server, values=servers, state="readonly"
|
||||
)
|
||||
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)
|
||||
|
||||
# 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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -85,7 +85,8 @@ def load(style):
|
|||
"fieldbackground": Colors.white,
|
||||
"foreground": Colors.black,
|
||||
"padding": (2, 0),
|
||||
}
|
||||
},
|
||||
"map": {"fieldbackground": [("disabled", Colors.frame)]},
|
||||
},
|
||||
"TCombobox": {
|
||||
"configure": {
|
||||
|
|
Loading…
Add table
Reference in a new issue