Merge branch 'coretk' into coretk-config

This commit is contained in:
Huy Pham 2019-11-11 10:58:30 -08:00
commit 2cc4ef5ac0
13 changed files with 491 additions and 647 deletions

View file

@ -65,12 +65,6 @@ class Application(tk.Frame):
def draw_status(self):
self.statusbar = tk.Frame(self)
self.statusbar.pack(side=tk.BOTTOM, fill=tk.X)
button = tk.Button(self.statusbar, text="Button 1")
button.pack(side=tk.LEFT, padx=1)
button = tk.Button(self.statusbar, text="Button 2")
button.pack(side=tk.LEFT, padx=1)
button = tk.Button(self.statusbar, text="Button 3")
button.pack(side=tk.LEFT, padx=1)
def on_closing(self):
menu_action = MenuAction(self, self.master)
@ -78,7 +72,8 @@ class Application(tk.Frame):
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
log_format = "%(asctime)s - %(levelname)s - %(module)s:%(funcName)s - %(message)s"
logging.basicConfig(level=logging.DEBUG, format=log_format)
appdirs.check_directory()
app = Application()
app.mainloop()

View file

@ -0,0 +1,134 @@
import tkinter as tk
from tkinter import ttk
class CanvasTooltip:
"""
It creates a tooltip for a given canvas tag or id as the mouse is
above it.
This class has been derived from the original Tooltip class updated
and posted back to StackOverflow at the following link:
https://stackoverflow.com/questions/3221956/
what-is-the-simplest-way-to-make-tooltips-in-tkinter/
41079350#41079350
Alberto Vassena on 2016.12.10.
"""
def __init__(
self,
canvas,
tag_or_id,
*,
bg="#FFFFEA",
pad=(5, 3, 5, 3),
text="canvas info",
waittime=400,
wraplength=250
):
# 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.bg = bg
self.pad = pad
self.id = None
self.tw = None
def on_enter(self, event=None):
self.schedule()
def on_leave(self, event=None):
self.unschedule()
self.hide()
def schedule(self):
self.unschedule()
self.id = self.canvas.after(self.waittime, self.show)
def unschedule(self):
id_ = self.id
self.id = None
if id_:
self.canvas.after_cancel(id_)
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
x_delta = x2 - s_width
if x_delta < 0:
x_delta = 0
y_delta = y2 - s_height
if y_delta < 0:
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
pad = self.pad
canvas = self.canvas
# creates a toplevel window
self.tw = tk.Toplevel(canvas.master)
# Leaves only the label and removes the app window
self.tw.wm_overrideredirect(True)
win = tk.Frame(self.tw, background=bg, borderwidth=0)
label = ttk.Label(
win,
text=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):
if self.tw:
self.tw.destroy()
self.tw = None

View file

@ -14,8 +14,8 @@ from coretk.mobilitynodeconfig import MobilityNodeConfig
from coretk.servicenodeconfig import ServiceNodeConfig
from coretk.wlannodeconfig import WlanNodeConfig
link_layer_nodes = ["switch", "hub", "wlan", "rj45", "tunnel", "emane"]
network_layer_nodes = ["router", "host", "PC", "mdr", "prouter"]
NETWORK_NODES = {"switch", "hub", "wlan", "rj45", "tunnel", "emane"}
DEFAULT_NODES = {"router", "host", "PC", "mdr", "prouter"}
class Node:
@ -418,6 +418,9 @@ class CoreClient:
else:
return self.reusable.pop(0)
def is_model_node(self, name):
return name in DEFAULT_NODES or name in self.custom_nodes
def add_graph_node(self, session_id, canvas_id, x, y, name):
"""
Add node, with information filled in, to grpc manager
@ -431,7 +434,7 @@ class CoreClient:
"""
node_type = None
node_model = None
if name in link_layer_nodes:
if name in NETWORK_NODES:
if name == "switch":
node_type = core_pb2.NodeType.SWITCH
elif name == "hub":
@ -446,7 +449,7 @@ class CoreClient:
node_type = core_pb2.NodeType.TUNNEL
elif name == "emane":
node_type = core_pb2.NodeType.EMANE
elif name in network_layer_nodes:
elif self.is_model_node(name):
node_type = core_pb2.NodeType.DEFAULT
node_model = name
else:
@ -621,7 +624,7 @@ class CoreClient:
self.interfaces_manager.new_subnet()
src_node = self.nodes[src_canvas_id]
if src_node.model in network_layer_nodes:
if self.is_model_node(src_node.model):
ifid = len(src_node.interfaces)
name = "eth" + str(ifid)
src_interface = Interface(
@ -635,7 +638,7 @@ class CoreClient:
)
dst_node = self.nodes[dst_canvas_id]
if dst_node.model in network_layer_nodes:
if self.is_model_node(dst_node.model):
ifid = len(dst_node.interfaces)
name = "eth" + str(ifid)
dst_interface = Interface(

View file

@ -15,7 +15,7 @@ class ServicesSelectDialog(Dialog):
self.groups = None
self.services = None
self.current = None
self.current_services = current_services
self.current_services = set(current_services)
self.draw()
def draw(self):
@ -48,7 +48,7 @@ class ServicesSelectDialog(Dialog):
frame.grid(stick="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Save", command=self.click_cancel)
button = tk.Button(frame, text="Save", command=self.destroy)
button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.click_cancel)
button.grid(row=0, column=1, sticky="ew")
@ -174,7 +174,8 @@ class CustomNodesDialog(Dialog):
dialog = ServicesSelectDialog(self, self.app, self.services)
dialog.show()
if dialog.current_services is not None:
self.services = dialog.current_services
self.services.clear()
self.services.update(dialog.current_services)
def click_save(self):
self.app.config["nodes"].clear()
@ -208,7 +209,7 @@ class CustomNodesDialog(Dialog):
custom_node = self.app.core.custom_nodes.pop(previous_name)
custom_node.name = name
custom_node.image = self.image
custom_node.image_file = Path(self.image_file).name
custom_node.image_file = Path(self.image_file).stem
custom_node.services = self.services
self.app.core.custom_nodes[name] = custom_node
self.nodes_list.listbox.delete(self.selected_index)

View file

@ -4,6 +4,7 @@ import tkinter as tk
from core.api.grpc import core_pb2
from coretk.canvasaction import CanvasAction
from coretk.canvastooltip import CanvasTooltip
from coretk.graph_helper import GraphHelper, WlanAntennaManager
from coretk.images import Images
from coretk.interface import Interface
@ -512,6 +513,7 @@ class CanvasNode:
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.edges = set()
self.wlans = []

View file

@ -17,214 +17,6 @@ from coretk.dialogs.sessionoptions import SessionOptionsDialog
from coretk.dialogs.sessions import SessionsDialog
def sub_menu_items():
logging.debug("Click on sub menu items")
def file_new(event=None):
logging.debug("Click file New")
def file_reload():
logging.debug("Click file Reload")
def file_export_python_script():
logging.debug("Click file export python script")
def file_execute_xml_or_python_script():
logging.debug("Execute XML or Python script")
def file_execute_python_script_with_options():
logging.debug("Click execute Python script with options")
def file_open_current_file_in_editor():
logging.debug("Click file open current in editor")
def file_print():
logging.debug("Click file Print")
def file_save_screenshot():
logging.debug("Click file save screenshot")
def edit_undo(event=None):
logging.debug("Click edit undo")
def edit_redo(event=None):
logging.debug("Click edit redo")
def edit_cut(event=None):
logging.debug("Click edit cut")
def edit_copy(event=None):
logging.debug("Click edit copy")
def edit_paste(event=None):
logging.debug("Click edit paste")
def edit_select_all(event=None):
logging.debug("Click edit select all")
def edit_select_adjacent(event=None):
logging.debug("Click edit select adjacent")
def edit_find(event=None):
logging.debug("CLick edit find")
def edit_clear_marker():
logging.debug("Click edit clear marker")
def edit_preferences():
logging.debug("Click preferences")
def canvas_new():
logging.debug("Click canvas new")
def canvas_manage():
logging.debug("Click canvas manage")
def canvas_delete():
logging.debug("Click canvas delete")
def canvas_previous(event=None):
logging.debug("Click canvas previous")
def canvas_next(event=None):
logging.debug("Click canvas next")
def canvas_first(event=None):
logging.debug("CLick canvas first")
def canvas_last(event=None):
logging.debug("CLick canvas last")
def view_show():
logging.debug("Click view show")
def view_show_hidden_nodes():
logging.debug("Click view show hidden nodes")
def view_locked():
logging.debug("Click view locked")
def view_3d_gui():
logging.debug("CLick view 3D GUI")
def view_zoom_in(event=None):
logging.debug("Click view zoom in")
def view_zoom_out(event=None):
logging.debug("Click view zoom out")
def tools_auto_rearrange_all():
logging.debug("Click tools, auto rearrange all")
def tools_auto_rearrange_selected():
logging.debug("CLick tools auto rearrange selected")
def tools_align_to_grid():
logging.debug("Click tools align to grid")
def tools_traffic():
logging.debug("Click tools traffic")
def tools_ip_addresses():
logging.debug("Click tools ip addresses")
def tools_mac_addresses():
logging.debug("Click tools mac addresses")
def tools_build_hosts_file():
logging.debug("Click tools build hosts file")
def tools_renumber_nodes():
logging.debug("Click tools renumber nodes")
def tools_experimental():
logging.debug("Click tools experimental")
def tools_topology_generator():
logging.debug("Click tools topology generator")
def tools_debugger():
logging.debug("Click tools debugger")
def widgets_observer_widgets():
logging.debug("Click widgets observer widgets")
def widgets_adjacency():
logging.debug("Click widgets adjacency")
def widgets_throughput():
logging.debug("Click widgets throughput")
def widgets_configure_adjacency():
logging.debug("Click widgets configure adjacency")
def widgets_configure_throughput():
logging.debug("Click widgets configure throughput")
def session_node_types():
logging.debug("Click session node types")
def session_comments():
logging.debug("Click session comments")
def session_reset_node_positions():
logging.debug("Click session reset node positions")
def help_about():
logging.debug("Click help About")
class MenuAction:
"""
Actions performed when choosing menu items
@ -258,7 +50,7 @@ class MenuAction:
self.app.core.stop_session()
self.app.core.delete_session()
def on_quit(self):
def on_quit(self, event=None):
"""
Prompt user whether so save running session, and then close the application

View file

@ -43,52 +43,33 @@ class Menubar(tk.Menu):
:return: nothing
"""
file_menu = tk.Menu(self)
file_menu.add_command(
label="New Session",
command=action.file_new,
accelerator="Ctrl+N",
underline=0,
)
self.app.bind_all("<Control-n>", action.file_new)
file_menu.add_command(
label="Open...",
command=self.menuaction.file_open_xml,
accelerator="Ctrl+O",
underline=0,
menu = tk.Menu(self)
menu.add_command(label="New Session", accelerator="Ctrl+N", state=tk.DISABLED)
menu.add_command(
label="Open...", command=self.menuaction.file_open_xml, accelerator="Ctrl+O"
)
self.app.bind_all("<Control-o>", self.menuaction.file_open_xml)
file_menu.add_command(label="Reload", command=action.file_reload, underline=0)
file_menu.add_command(
menu.add_command(label="Reload", underline=0, state=tk.DISABLED)
menu.add_command(
label="Save", accelerator="Ctrl+S", command=self.menuaction.file_save_as_xml
)
self.app.bind_all("<Control-s>", self.menuaction.file_save_as_xml)
file_menu.add_separator()
file_menu.add_command(
label="Export Python script...", command=action.file_export_python_script
menu.add_separator()
menu.add_command(label="Export Python script...", state=tk.DISABLED)
menu.add_command(label="Execute XML or Python script...", state=tk.DISABLED)
menu.add_command(
label="Execute Python script with options...", state=tk.DISABLED
)
file_menu.add_command(
label="Execute XML or Python script...",
command=action.file_execute_xml_or_python_script,
menu.add_separator()
menu.add_command(label="Open current file in editor...", state=tk.DISABLED)
menu.add_command(label="Print...", underline=0, state=tk.DISABLED)
menu.add_command(label="Save screenshot...", state=tk.DISABLED)
menu.add_separator()
menu.add_command(
label="Quit", accelerator="Ctrl+Q", command=self.menuaction.on_quit
)
file_menu.add_command(
label="Execute Python script with options...",
command=action.file_execute_python_script_with_options,
)
file_menu.add_separator()
file_menu.add_command(
label="Open current file in editor...",
command=action.file_open_current_file_in_editor,
)
file_menu.add_command(label="Print...", command=action.file_print, underline=0)
file_menu.add_command(
label="Save screenshot...", command=action.file_save_screenshot
)
file_menu.add_separator()
file_menu.add_command(
label="Quit", command=self.menuaction.on_quit, underline=0
)
self.add_cascade(label="File", menu=file_menu, underline=0)
self.app.bind_all("<Control-q>", self.menuaction.on_quit)
self.add_cascade(label="File", menu=menu)
def draw_edit_menu(self):
"""
@ -96,47 +77,23 @@ class Menubar(tk.Menu):
:return: nothing
"""
edit_menu = tk.Menu(self)
edit_menu.add_command(
label="Undo", command=action.edit_undo, accelerator="Ctrl+Z", underline=0
menu = tk.Menu(self)
menu.add_command(label="Undo", accelerator="Ctrl+Z", state=tk.DISABLED)
menu.add_command(label="Redo", accelerator="Ctrl+Y", state=tk.DISABLED)
menu.add_separator()
menu.add_command(label="Cut", accelerator="Ctrl+X", state=tk.DISABLED)
menu.add_command(label="Copy", accelerator="Ctrl+C", state=tk.DISABLED)
menu.add_command(label="Paste", accelerator="Ctrl+V", state=tk.DISABLED)
menu.add_separator()
menu.add_command(label="Select all", accelerator="Ctrl+A", state=tk.DISABLED)
menu.add_command(
label="Select Adjacent", accelerator="Ctrl+J", state=tk.DISABLED
)
self.app.bind_all("<Control-z>", action.edit_undo)
edit_menu.add_command(
label="Redo", command=action.edit_redo, accelerator="Ctrl+Y", underline=0
)
self.app.bind_all("<Control-y>", action.edit_redo)
edit_menu.add_separator()
edit_menu.add_command(
label="Cut", command=action.edit_cut, accelerator="Ctrl+X", underline=0
)
self.app.bind_all("<Control-x>", action.edit_cut)
edit_menu.add_command(
label="Copy", command=action.edit_copy, accelerator="Ctrl+C", underline=0
)
self.app.bind_all("<Control-c>", action.edit_copy)
edit_menu.add_command(
label="Paste", command=action.edit_paste, accelerator="Ctrl+V", underline=0
)
self.app.bind_all("<Control-v>", action.edit_paste)
edit_menu.add_separator()
edit_menu.add_command(
label="Select all", command=action.edit_select_all, accelerator="Ctrl+A"
)
self.app.bind_all("<Control-a>", action.edit_select_all)
edit_menu.add_command(
label="Select Adjacent",
command=action.edit_select_adjacent,
accelerator="Ctrl+J",
)
self.app.bind_all("<Control-j>", action.edit_select_adjacent)
edit_menu.add_separator()
edit_menu.add_command(
label="Find...", command=action.edit_find, accelerator="Ctrl+F", underline=0
)
self.app.bind_all("<Control-f>", action.edit_find)
edit_menu.add_command(label="Clear marker", command=action.edit_clear_marker)
edit_menu.add_command(label="Preferences...", command=action.edit_preferences)
self.add_cascade(label="Edit", menu=edit_menu, underline=0)
menu.add_separator()
menu.add_command(label="Find...", accelerator="Ctrl+F", state=tk.DISABLED)
menu.add_command(label="Clear marker", state=tk.DISABLED)
menu.add_command(label="Preferences...", state=tk.DISABLED)
self.add_cascade(label="Edit", menu=menu)
def draw_canvas_menu(self):
"""
@ -144,55 +101,23 @@ class Menubar(tk.Menu):
:return: nothing
"""
canvas_menu = tk.Menu(self)
canvas_menu.add_command(label="New", command=action.canvas_new)
canvas_menu.add_command(label="Manage...", command=action.canvas_manage)
canvas_menu.add_command(label="Delete", command=action.canvas_delete)
canvas_menu.add_separator()
canvas_menu.add_command(
menu = tk.Menu(self)
menu.add_command(label="New", state=tk.DISABLED)
menu.add_command(label="Manage...", state=tk.DISABLED)
menu.add_command(label="Delete", state=tk.DISABLED)
menu.add_separator()
menu.add_command(
label="Size/scale...", command=self.menuaction.canvas_size_and_scale
)
canvas_menu.add_command(
menu.add_command(
label="Wallpaper...", command=self.menuaction.canvas_set_wallpaper
)
canvas_menu.add_separator()
canvas_menu.add_command(
label="Previous", command=action.canvas_previous, accelerator="PgUp"
)
self.app.bind_all("<Prior>", action.canvas_previous)
canvas_menu.add_command(
label="Next", command=action.canvas_next, accelerator="PgDown"
)
self.app.bind_all("<Next>", action.canvas_next)
canvas_menu.add_command(
label="First", command=action.canvas_first, accelerator="Home"
)
self.app.bind_all("<Home>", action.canvas_first)
canvas_menu.add_command(
label="Last", command=action.canvas_last, accelerator="End"
)
self.app.bind_all("<End>", action.canvas_last)
self.add_cascade(label="Canvas", menu=canvas_menu, underline=0)
def create_show_menu(self, view_menu):
"""
Create the menu items in View/Show
:param tkinter.Menu view_menu: the view menu
:return: nothing
"""
show_menu = tk.Menu(view_menu)
show_menu.add_command(label="All", command=action.sub_menu_items)
show_menu.add_command(label="None", command=action.sub_menu_items)
show_menu.add_separator()
show_menu.add_command(label="Interface Names", command=action.sub_menu_items)
show_menu.add_command(label="IPv4 Addresses", command=action.sub_menu_items)
show_menu.add_command(label="IPv6 Addresses", command=action.sub_menu_items)
show_menu.add_command(label="Node Labels", command=action.sub_menu_items)
show_menu.add_command(label="Annotations", command=action.sub_menu_items)
show_menu.add_command(label="Grid", command=action.sub_menu_items)
show_menu.add_command(label="API Messages", command=action.sub_menu_items)
view_menu.add_cascade(label="Show", menu=show_menu)
menu.add_separator()
menu.add_command(label="Previous", accelerator="PgUp", state=tk.DISABLED)
menu.add_command(label="Next", accelerator="PgDown", state=tk.DISABLED)
menu.add_command(label="First", accelerator="Home", state=tk.DISABLED)
menu.add_command(label="Last", accelerator="End", state=tk.DISABLED)
self.add_cascade(label="Canvas", menu=menu)
def draw_view_menu(self):
"""
@ -202,21 +127,33 @@ class Menubar(tk.Menu):
"""
view_menu = tk.Menu(self)
self.create_show_menu(view_menu)
view_menu.add_command(
label="Show hidden nodes", command=action.view_show_hidden_nodes
)
view_menu.add_command(label="Locked", command=action.view_locked)
view_menu.add_command(label="3D GUI...", command=action.view_3d_gui)
view_menu.add_command(label="Show hidden nodes", state=tk.DISABLED)
view_menu.add_command(label="Locked", state=tk.DISABLED)
view_menu.add_command(label="3D GUI...", state=tk.DISABLED)
view_menu.add_separator()
view_menu.add_command(
label="Zoom in", command=action.view_zoom_in, accelerator="+"
)
self.app.bind_all("<Control-Shift-plus>", action.view_zoom_in)
view_menu.add_command(
label="Zoom out", command=action.view_zoom_out, accelerator="-"
)
self.app.bind_all("<Control-minus>", action.view_zoom_out)
self.add_cascade(label="View", menu=view_menu, underline=0)
view_menu.add_command(label="Zoom in", accelerator="+", state=tk.DISABLED)
view_menu.add_command(label="Zoom out", accelerator="-", state=tk.DISABLED)
self.add_cascade(label="View", menu=view_menu)
def create_show_menu(self, view_menu):
"""
Create the menu items in View/Show
:param tkinter.Menu view_menu: the view menu
:return: nothing
"""
menu = tk.Menu(view_menu)
menu.add_command(label="All", state=tk.DISABLED)
menu.add_command(label="None", state=tk.DISABLED)
menu.add_separator()
menu.add_command(label="Interface Names", state=tk.DISABLED)
menu.add_command(label="IPv4 Addresses", state=tk.DISABLED)
menu.add_command(label="IPv6 Addresses", state=tk.DISABLED)
menu.add_command(label="Node Labels", state=tk.DISABLED)
menu.add_command(label="Annotations", state=tk.DISABLED)
menu.add_command(label="Grid", state=tk.DISABLED)
menu.add_command(label="API Messages", state=tk.DISABLED)
view_menu.add_cascade(label="Show", menu=menu)
def create_experimental_menu(self, tools_menu):
"""
@ -225,19 +162,11 @@ class Menubar(tk.Menu):
:param tkinter.Menu tools_menu: tools menu
:return: nothing
"""
experimental_menu = tk.Menu(tools_menu)
experimental_menu.add_command(
label="Plugins...", command=action.sub_menu_items, underline=0
)
experimental_menu.add_command(
label="ns2immunes converter...", command=action.sub_menu_items, underline=0
)
experimental_menu.add_command(
label="Topology partitioning...", command=action.sub_menu_items
)
tools_menu.add_cascade(
label="Experimental", menu=experimental_menu, underline=0
)
menu = tk.Menu(tools_menu)
menu.add_command(label="Plugins...", state=tk.DISABLED)
menu.add_command(label="ns2immunes converter...", state=tk.DISABLED)
menu.add_command(label="Topology partitioning...", state=tk.DISABLED)
tools_menu.add_cascade(label="Experimental", menu=menu)
def create_random_menu(self, topology_generator_menu):
"""
@ -246,15 +175,13 @@ class Menubar(tk.Menu):
:param tkinter.Menu topology_generator_menu: topology generator menu
:return: nothing
"""
random_menu = tk.Menu(topology_generator_menu)
menu = tk.Menu(topology_generator_menu)
# list of number of random nodes to create
nums = [1, 5, 10, 15, 20, 30, 40, 50, 75, 100]
for i in nums:
the_label = "R(" + str(i) + ")"
random_menu.add_command(label=the_label, command=action.sub_menu_items)
topology_generator_menu.add_cascade(
label="Random", menu=random_menu, underline=0
)
label = f"R({i})"
menu.add_command(label=label, state=tk.DISABLED)
topology_generator_menu.add_cascade(label="Random", menu=menu)
def create_grid_menu(self, topology_generator_menu):
"""
@ -263,13 +190,13 @@ class Menubar(tk.Menu):
:param tkinter.Menu topology_generator_menu: topology_generator_menu
:return: nothing
"""
grid_menu = tk.Menu(topology_generator_menu)
menu = tk.Menu(topology_generator_menu)
# list of number of nodes to create
nums = [1, 5, 10, 15, 20, 25, 30, 35, 40, 50, 60, 70, 80, 90, 100]
for i in nums:
the_label = "G(" + str(i) + ")"
grid_menu.add_command(label=the_label, command=action.sub_menu_items)
topology_generator_menu.add_cascade(label="Grid", menu=grid_menu, underline=0)
label = f"G({i})"
menu.add_command(label=label, state=tk.DISABLED)
topology_generator_menu.add_cascade(label="Grid", menu=menu)
def create_connected_grid_menu(self, topology_generator_menu):
"""
@ -278,17 +205,15 @@ class Menubar(tk.Menu):
:param tkinter.Menu topology_generator_menu: topology generator menu
:return: nothing
"""
grid_menu = tk.Menu(topology_generator_menu)
menu = tk.Menu(topology_generator_menu)
for i in range(1, 11, 1):
i_n_menu = tk.Menu(grid_menu)
submenu = tk.Menu(menu)
for j in range(1, 11, 1):
i_j_label = str(i) + " X " + str(j)
i_n_menu.add_command(label=i_j_label, command=action.sub_menu_items)
i_n_label = str(i) + " X N"
grid_menu.add_cascade(label=i_n_label, menu=i_n_menu)
topology_generator_menu.add_cascade(
label="Connected Grid", menu=grid_menu, underline=0
)
label = f"{i} X {j}"
submenu.add_command(label=label, state=tk.DISABLED)
label = str(i) + " X N"
menu.add_cascade(label=label, menu=submenu)
topology_generator_menu.add_cascade(label="Connected Grid", menu=menu)
def create_chain_menu(self, topology_generator_menu):
"""
@ -297,13 +222,13 @@ class Menubar(tk.Menu):
:param tkinter.Menu topology_generator_menu: topology generator menu
:return: nothing
"""
chain_menu = tk.Menu(topology_generator_menu)
menu = tk.Menu(topology_generator_menu)
# number of nodes to create
nums = list(range(2, 25, 1)) + [32, 64, 128]
for i in nums:
the_label = "P(" + str(i) + ")"
chain_menu.add_command(label=the_label, command=action.sub_menu_items)
topology_generator_menu.add_cascade(label="Chain", menu=chain_menu, underline=0)
label = f"P({i})"
menu.add_command(label=label, state=tk.DISABLED)
topology_generator_menu.add_cascade(label="Chain", menu=menu)
def create_star_menu(self, topology_generator_menu):
"""
@ -312,11 +237,11 @@ class Menubar(tk.Menu):
:param tkinter.Menu topology_generator_menu: topology generator menu
:return: nothing
"""
star_menu = tk.Menu(topology_generator_menu)
menu = tk.Menu(topology_generator_menu)
for i in range(3, 26, 1):
the_label = "C(" + str(i) + ")"
star_menu.add_command(label=the_label, command=action.sub_menu_items)
topology_generator_menu.add_cascade(label="Star", menu=star_menu, underline=0)
label = f"C({i})"
menu.add_command(label=label, state=tk.DISABLED)
topology_generator_menu.add_cascade(label="Star", menu=menu)
def create_cycle_menu(self, topology_generator_menu):
"""
@ -325,11 +250,11 @@ class Menubar(tk.Menu):
:param tkinter.Menu topology_generator_menu: topology generator menu
:return: nothing
"""
cycle_menu = tk.Menu(topology_generator_menu)
menu = tk.Menu(topology_generator_menu)
for i in range(3, 25, 1):
the_label = "C(" + str(i) + ")"
cycle_menu.add_command(label=the_label, command=action.sub_menu_items)
topology_generator_menu.add_cascade(label="Cycle", menu=cycle_menu, underline=0)
label = f"C({i})"
menu.add_command(label=label, state=tk.DISABLED)
topology_generator_menu.add_cascade(label="Cycle", menu=menu)
def create_wheel_menu(self, topology_generator_menu):
"""
@ -338,11 +263,11 @@ class Menubar(tk.Menu):
:param tkinter.Menu topology_generator_menu: topology generator menu
:return: nothing
"""
wheel_menu = tk.Menu(topology_generator_menu)
menu = tk.Menu(topology_generator_menu)
for i in range(4, 26, 1):
the_label = "W(" + str(i) + ")"
wheel_menu.add_command(label=the_label, command=action.sub_menu_items)
topology_generator_menu.add_cascade(label="Wheel", menu=wheel_menu, underline=0)
label = f"W({i})"
menu.add_command(label=label, state=tk.DISABLED)
topology_generator_menu.add_cascade(label="Wheel", menu=menu)
def create_cube_menu(self, topology_generator_menu):
"""
@ -351,11 +276,11 @@ class Menubar(tk.Menu):
:param tkinter.Menu topology_generator_menu: topology generator menu
:return: nothing
"""
cube_menu = tk.Menu(topology_generator_menu)
menu = tk.Menu(topology_generator_menu)
for i in range(2, 7, 1):
the_label = "Q(" + str(i) + ")"
cube_menu.add_command(label=the_label, command=action.sub_menu_items)
topology_generator_menu.add_cascade(label="Cube", menu=cube_menu, underline=0)
label = f"Q({i})"
menu.add_command(label=label, state=tk.DISABLED)
topology_generator_menu.add_cascade(label="Cube", menu=menu)
def create_clique_menu(self, topology_generator_menu):
"""
@ -364,13 +289,11 @@ class Menubar(tk.Menu):
:param tkinter.Menu topology_generator_menu: topology generator menu
:return: nothing
"""
clique_menu = tk.Menu(topology_generator_menu)
menu = tk.Menu(topology_generator_menu)
for i in range(3, 25, 1):
the_label = "K(" + str(i) + ")"
clique_menu.add_command(label=the_label, command=action.sub_menu_items)
topology_generator_menu.add_cascade(
label="Clique", menu=clique_menu, underline=0
)
label = f"K({i})"
menu.add_command(label=label, state=tk.DISABLED)
topology_generator_menu.add_cascade(label="Clique", menu=menu)
def create_bipartite_menu(self, topology_generator_menu):
"""
@ -379,19 +302,17 @@ class Menubar(tk.Menu):
:param tkinter.Menu topology_generator_menu: topology_generator_menu
:return: nothing
"""
bipartite_menu = tk.Menu(topology_generator_menu)
menu = tk.Menu(topology_generator_menu)
temp = 24
for i in range(1, 13, 1):
i_n_menu = tk.Menu(bipartite_menu)
submenu = tk.Menu(menu)
for j in range(i, temp, 1):
i_j_label = "K(" + str(i) + " X " + str(j) + ")"
i_n_menu.add_command(label=i_j_label, command=action.sub_menu_items)
i_n_label = "K(" + str(i) + " X N)"
bipartite_menu.add_cascade(label=i_n_label, menu=i_n_menu)
label = f"K({i} X {j})"
submenu.add_command(label=label, state=tk.DISABLED)
label = f"K({i})"
menu.add_cascade(label=label, menu=submenu)
temp = temp - 1
topology_generator_menu.add_cascade(
label="Bipartite", menu=bipartite_menu, underline=0
)
topology_generator_menu.add_cascade(label="Bipartite", menu=menu)
def create_topology_generator_menu(self, tools_menu):
"""
@ -401,20 +322,18 @@ class Menubar(tk.Menu):
:return: nothing
"""
topology_generator_menu = tk.Menu(tools_menu)
self.create_random_menu(topology_generator_menu)
self.create_grid_menu(topology_generator_menu)
self.create_connected_grid_menu(topology_generator_menu)
self.create_chain_menu(topology_generator_menu)
self.create_star_menu(topology_generator_menu)
self.create_cycle_menu(topology_generator_menu)
self.create_wheel_menu(topology_generator_menu)
self.create_cube_menu(topology_generator_menu)
self.create_clique_menu(topology_generator_menu)
self.create_bipartite_menu(topology_generator_menu)
tools_menu.add_cascade(
label="Topology generator", menu=topology_generator_menu, underline=0
)
menu = tk.Menu(tools_menu)
self.create_random_menu(menu)
self.create_grid_menu(menu)
self.create_connected_grid_menu(menu)
self.create_chain_menu(menu)
self.create_star_menu(menu)
self.create_cycle_menu(menu)
self.create_wheel_menu(menu)
self.create_cube_menu(menu)
self.create_clique_menu(menu)
self.create_bipartite_menu(menu)
tools_menu.add_cascade(label="Topology generator", menu=menu)
def draw_tools_menu(self):
"""
@ -422,41 +341,21 @@ class Menubar(tk.Menu):
:return: nothing
"""
tools_menu = tk.Menu(self)
tools_menu.add_command(
label="Auto rearrange all",
command=action.tools_auto_rearrange_all,
underline=0,
)
tools_menu.add_command(
label="Auto rearrange selected",
command=action.tools_auto_rearrange_selected,
underline=0,
)
tools_menu.add_separator()
tools_menu.add_command(
label="Align to grid", command=action.tools_align_to_grid, underline=0
)
tools_menu.add_separator()
tools_menu.add_command(label="Traffic...", command=action.tools_traffic)
tools_menu.add_command(
label="IP addresses...", command=action.tools_ip_addresses, underline=0
)
tools_menu.add_command(
label="MAC addresses...", command=action.tools_mac_addresses, underline=0
)
tools_menu.add_command(
label="Build hosts file...",
command=action.tools_build_hosts_file,
underline=0,
)
tools_menu.add_command(
label="Renumber nodes...", command=action.tools_renumber_nodes, underline=0
)
self.create_experimental_menu(tools_menu)
self.create_topology_generator_menu(tools_menu)
tools_menu.add_command(label="Debugger...", command=action.tools_debugger)
self.add_cascade(label="Tools", menu=tools_menu, underline=0)
menu = tk.Menu(self)
menu.add_command(label="Auto rearrange all", state=tk.DISABLED)
menu.add_command(label="Auto rearrange selected", state=tk.DISABLED)
menu.add_separator()
menu.add_command(label="Align to grid", state=tk.DISABLED)
menu.add_separator()
menu.add_command(label="Traffic...", state=tk.DISABLED)
menu.add_command(label="IP addresses...", state=tk.DISABLED)
menu.add_command(label="MAC addresses...", state=tk.DISABLED)
menu.add_command(label="Build hosts file...", state=tk.DISABLED)
menu.add_command(label="Renumber nodes...", state=tk.DISABLED)
self.create_experimental_menu(menu)
self.create_topology_generator_menu(menu)
menu.add_command(label="Debugger...", state=tk.DISABLED)
self.add_cascade(label="Tools", menu=menu)
def create_observer_widgets_menu(self, widget_menu):
"""
@ -465,54 +364,24 @@ class Menubar(tk.Menu):
:param tkinter.Menu widget_menu: widget_menu
:return: nothing
"""
observer_widget_menu = tk.Menu(widget_menu)
observer_widget_menu.add_command(label="None", command=action.sub_menu_items)
observer_widget_menu.add_command(
label="processes", command=action.sub_menu_items
)
observer_widget_menu.add_command(
label="ifconfig", command=action.sub_menu_items
)
observer_widget_menu.add_command(
label="IPv4 routes", command=action.sub_menu_items
)
observer_widget_menu.add_command(
label="IPv6 routes", command=action.sub_menu_items
)
observer_widget_menu.add_command(
label="OSPFv2 neighbors", command=action.sub_menu_items
)
observer_widget_menu.add_command(
label="OSPFv3 neighbors", command=action.sub_menu_items
)
observer_widget_menu.add_command(
label="Listening sockets", command=action.sub_menu_items
)
observer_widget_menu.add_command(
label="IPv4 MFC entries", command=action.sub_menu_items
)
observer_widget_menu.add_command(
label="IPv6 MFC entries", command=action.sub_menu_items
)
observer_widget_menu.add_command(
label="firewall rules", command=action.sub_menu_items
)
observer_widget_menu.add_command(
label="IPsec policies", command=action.sub_menu_items
)
observer_widget_menu.add_command(
label="docker logs", command=action.sub_menu_items
)
observer_widget_menu.add_command(
label="OSPFv3 MDR level", command=action.sub_menu_items
)
observer_widget_menu.add_command(
label="PIM neighbors", command=action.sub_menu_items
)
observer_widget_menu.add_command(
label="Edit...", command=self.menuaction.edit_observer_widgets
)
widget_menu.add_cascade(label="Observer Widgets", menu=observer_widget_menu)
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)
widget_menu.add_cascade(label="Observer Widgets", menu=menu)
def create_adjacency_menu(self, widget_menu):
"""
@ -521,12 +390,12 @@ class Menubar(tk.Menu):
:param tkinter.Menu widget_menu: widget menu
:return: nothing
"""
adjacency_menu = tk.Menu(widget_menu)
adjacency_menu.add_command(label="OSPFv2", command=action.sub_menu_items)
adjacency_menu.add_command(label="OSPFv3", command=action.sub_menu_items)
adjacency_menu.add_command(label="OSLR", command=action.sub_menu_items)
adjacency_menu.add_command(label="OSLRv2", command=action.sub_menu_items)
widget_menu.add_cascade(label="Adjacency", menu=adjacency_menu)
menu = tk.Menu(widget_menu)
menu.add_command(label="OSPFv2", state=tk.DISABLED)
menu.add_command(label="OSPFv3", state=tk.DISABLED)
menu.add_command(label="OSLR", state=tk.DISABLED)
menu.add_command(label="OSLRv2", state=tk.DISABLED)
widget_menu.add_cascade(label="Adjacency", menu=menu)
def draw_widgets_menu(self):
"""
@ -534,18 +403,14 @@ class Menubar(tk.Menu):
:return: nothing
"""
widget_menu = tk.Menu(self)
self.create_observer_widgets_menu(widget_menu)
self.create_adjacency_menu(widget_menu)
widget_menu.add_command(label="Throughput", command=action.widgets_throughput)
widget_menu.add_separator()
widget_menu.add_command(
label="Configure Adjacency...", command=action.widgets_configure_adjacency
)
widget_menu.add_command(
label="Configure Throughput...", command=action.widgets_configure_throughput
)
self.add_cascade(label="Widgets", menu=widget_menu, underline=0)
menu = tk.Menu(self)
self.create_observer_widgets_menu(menu)
self.create_adjacency_menu(menu)
menu.add_command(label="Throughput", state=tk.DISABLED)
menu.add_separator()
menu.add_command(label="Configure Adjacency...", state=tk.DISABLED)
menu.add_command(label="Configure Throughput...", state=tk.DISABLED)
self.add_cascade(label="Widgets", menu=menu)
def draw_session_menu(self):
"""
@ -553,36 +418,21 @@ class Menubar(tk.Menu):
:return: nothing
"""
session_menu = tk.Menu(self)
session_menu.add_command(
menu = tk.Menu(self)
menu.add_command(
label="Change sessions...",
command=self.menuaction.session_change_sessions,
underline=0,
)
session_menu.add_separator()
session_menu.add_command(
label="Node types...", command=action.session_node_types, underline=0
menu.add_separator()
menu.add_command(label="Comments...", state=tk.DISABLED)
menu.add_command(label="Hooks...", command=self.menuaction.session_hooks)
menu.add_command(label="Reset node positions", state=tk.DISABLED)
menu.add_command(
label="Emulation servers...", command=self.menuaction.session_servers
)
session_menu.add_command(
label="Comments...", command=action.session_comments, underline=0
)
session_menu.add_command(
label="Hooks...", command=self.menuaction.session_hooks, underline=0
)
session_menu.add_command(
label="Reset node positions",
command=action.session_reset_node_positions,
underline=0,
)
session_menu.add_command(
label="Emulation servers...",
command=self.menuaction.session_servers,
underline=0,
)
session_menu.add_command(
label="Options...", command=self.menuaction.session_options, underline=0
)
self.add_cascade(label="Session", menu=session_menu, underline=0)
menu.add_command(label="Options...", command=self.menuaction.session_options)
self.add_cascade(label="Session", menu=menu)
def draw_help_menu(self):
"""
@ -590,13 +440,13 @@ class Menubar(tk.Menu):
:return: nothing
"""
help_menu = tk.Menu(self)
help_menu.add_command(
menu = tk.Menu(self)
menu.add_command(
label="Core Github (www)", command=self.menuaction.help_core_github
)
help_menu.add_command(
menu.add_command(
label="Core Documentation (www)",
command=self.menuaction.help_core_documentation,
)
help_menu.add_command(label="About", command=action.help_about)
self.add_cascade(label="Help", menu=help_menu)
menu.add_command(label="About", state=tk.DISABLED)
self.add_cascade(label="Help", menu=menu)

View file

@ -83,8 +83,8 @@ class Toolbar(tk.Frame):
"link tool",
)
self.create_node_button()
self.create_link_layer_button()
self.create_marker_button()
self.create_network_button()
self.create_annotation_button()
self.radio_value.set(1)
def draw_runtime_frame(self):
@ -145,15 +145,23 @@ class Toolbar(tk.Frame):
(ImageEnum.PC, "PC"),
(ImageEnum.MDR, "mdr"),
(ImageEnum.PROUTER, "prouter"),
(ImageEnum.EDITNODE, "custom node types"),
]
# draw default nodes
for image_enum, tooltip in nodes:
self.create_button(
Images.get(image_enum),
partial(self.update_button, self.node_button, image_enum, tooltip),
self.node_picker,
tooltip,
)
image = Images.get(image_enum)
func = partial(self.update_button, self.node_button, image, tooltip)
self.create_button(image, func, self.node_picker, tooltip)
# draw custom nodes
for name in sorted(self.app.core.custom_nodes):
custom_node = self.app.core.custom_nodes[name]
image = custom_node.image
func = partial(self.update_button, self.node_button, image, name)
self.create_button(image, func, self.node_picker, name)
# draw edit node
image = Images.get(ImageEnum.EDITNODE)
self.create_button(
image, self.click_edit_node, self.node_picker, "custom nodes"
)
self.show_picker(self.node_button, self.node_picker)
def show_picker(self, button, picker):
@ -161,22 +169,24 @@ class Toolbar(tk.Frame):
x = button.winfo_rootx() - first_button.winfo_rootx() + 40
y = button.winfo_rooty() - first_button.winfo_rooty() - 1
picker.place(x=x, y=y)
self.app.bind_all("<Button-1>", lambda e: self.hide_pickers())
self.app.bind_all("<ButtonRelease-1>", lambda e: self.hide_pickers())
picker.wait_visibility()
picker.grab_set()
self.wait_window(picker)
self.app.unbind_all("<Button-1>")
self.app.unbind_all("<ButtonRelease-1>")
def create_button(self, img, func, frame, tooltip):
def create_button(self, image, func, frame, tooltip):
"""
Create button and put it on the frame
:param PIL.Image img: button image
:param PIL.Image image: button image
:param func: the command that is executed when button is clicked
:param tkinter.Frame frame: frame that contains the button
:param str tooltip: tooltip text
:return: nothing
"""
button = tk.Button(frame, width=self.width, height=self.height, image=img)
button.bind("<Button-1>", lambda e: func())
button = tk.Button(frame, width=self.width, height=self.height, image=image)
button.bind("<ButtonRelease-1>", lambda e: func())
button.grid(pady=1)
CreateToolTip(button, tooltip)
@ -221,19 +231,18 @@ class Toolbar(tk.Frame):
logging.debug("Click LINK button")
self.app.canvas.mode = GraphMode.EDGE
def update_button(self, button, image_enum, name):
logging.info("update button(%s): %s, %s", button, image_enum, name)
def click_edit_node(self):
self.hide_pickers()
if image_enum == ImageEnum.EDITNODE:
dialog = CustomNodesDialog(self.app, self.app)
dialog.show()
else:
image = Images.get(image_enum)
logging.info("updating button(%s): %s", button, name)
button.configure(image=image)
self.app.canvas.mode = GraphMode.NODE
self.app.canvas.draw_node_image = image
self.app.canvas.draw_node_name = name
dialog = CustomNodesDialog(self.app, self.app)
dialog.show()
def update_button(self, button, image, name):
logging.info("update button(%s): %s", button, name)
self.hide_pickers()
button.configure(image=image)
self.app.canvas.mode = GraphMode.NODE
self.app.canvas.draw_node_image = image
self.app.canvas.draw_node_name = name
def hide_pickers(self):
logging.info("hiding pickers")
@ -262,8 +271,8 @@ class Toolbar(tk.Frame):
width=self.width,
height=self.height,
image=router_image,
command=self.draw_node_picker,
)
self.node_button.bind("<ButtonRelease-1>", lambda e: self.draw_node_picker())
self.node_button.grid()
CreateToolTip(self.node_button, "Network-layer virtual nodes")
@ -285,15 +294,16 @@ class Toolbar(tk.Frame):
(ImageEnum.TUNNEL, "tunnel", "tunnel tool"),
]
for image_enum, name, tooltip in nodes:
image = Images.get(image_enum)
self.create_button(
Images.get(image_enum),
partial(self.update_button, self.network_button, image_enum, name),
image,
partial(self.update_button, self.network_button, image, name),
self.network_picker,
tooltip,
)
self.show_picker(self.network_button, self.network_picker)
def create_link_layer_button(self):
def create_network_button(self):
"""
Create link-layer node button and the options that represent different link-layer node types
@ -308,7 +318,9 @@ class Toolbar(tk.Frame):
width=self.width,
height=self.height,
image=hub_image,
command=self.draw_network_picker,
)
self.network_button.bind(
"<ButtonRelease-1>", lambda e: self.draw_network_picker()
)
self.network_button.grid()
CreateToolTip(self.network_button, "link-layer nodes")
@ -337,7 +349,7 @@ class Toolbar(tk.Frame):
)
self.show_picker(self.annotation_button, self.annotation_picker)
def create_marker_button(self):
def create_annotation_button(self):
"""
Create marker button and options that represent different marker types
@ -352,7 +364,9 @@ class Toolbar(tk.Frame):
width=self.width,
height=self.height,
image=marker_image,
command=self.draw_annotation_picker,
)
self.annotation_button.bind(
"<ButtonRelease-1>", lambda e: self.draw_annotation_picker()
)
self.annotation_button.grid()
CreateToolTip(self.annotation_button, "background annotation tools")

View file

@ -159,6 +159,8 @@ class CoreGrpcClient:
emane_model_configs=None,
wlan_configs=None,
mobility_configs=None,
service_configs=None,
service_file_configs=None,
):
"""
Start a session.
@ -169,9 +171,11 @@ class CoreGrpcClient:
:param core_pb2.SessionLocation location: location to set
:param list[core_pb2.Hook] hooks: session hooks to set
:param dict emane_config: emane configuration to set
:param list emane_model_configs: emane model configurations to set
:param list wlan_configs: wlan configurations to set
:param list mobility_configs: mobility configurations to set
:param list emane_model_configs: node emane model configurations
:param list wlan_configs: node wlan configurations
:param list mobility_configs: node mobility configurations
:param list service_configs: node service configurations
:param list service_file_configs: node service file configurations
:return: start session response
:rtype: core_pb2.StartSessionResponse
"""
@ -185,6 +189,8 @@ class CoreGrpcClient:
emane_model_configs=emane_model_configs,
wlan_configs=wlan_configs,
mobility_configs=mobility_configs,
service_configs=service_configs,
service_file_configs=service_file_configs,
)
return self.stub.StartSession(request)
@ -768,14 +774,14 @@ class CoreGrpcClient:
:rtype: core_pb2.SetNodeServiceResponse
:raises grpc.RpcError: when session or node doesn't exist
"""
request = core_pb2.SetNodeServiceRequest(
session_id=session_id,
config = core_pb2.ServiceConfig(
node_id=node_id,
service=service,
startup=startup,
validate=validate,
shutdown=shutdown,
)
request = core_pb2.SetNodeServiceRequest(session_id=session_id, config=config)
return self.stub.SetNodeService(request)
def set_node_service_file(self, session_id, node_id, service, file_name, data):
@ -791,12 +797,11 @@ class CoreGrpcClient:
:rtype: core_pb2.SetNodeServiceFileResponse
:raises grpc.RpcError: when session or node doesn't exist
"""
config = core_pb2.ServiceFileConfig(
node_id=node_id, service=service, file=file_name, data=data
)
request = core_pb2.SetNodeServiceFileRequest(
session_id=session_id,
node_id=node_id,
service=service,
file=file_name,
data=data,
session_id=session_id, config=config
)
return self.stub.SetNodeServiceFile(request)

View file

@ -319,3 +319,18 @@ def session_location(session, location):
session.location.refxyz = (location.x, location.y, location.z)
session.location.setrefgeo(location.lat, location.lon, location.alt)
session.location.refscale = location.scale
def service_configuration(session, config):
"""
Convenience method for setting a node service configuration.
:param core.emulator.session.Session session: session for service configuration
:param core_pb2.ServiceConfig config: service configuration
:return:
"""
session.services.set_service(config.node_id, config.service)
service = session.services.get_service(config.node_id, config.service)
service.startup = tuple(config.startup)
service.validate = tuple(config.validate)
service.shutdown = tuple(config.shutdown)

View file

@ -153,6 +153,16 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
config.node_id, Ns2ScriptedMobility.name, config.config
)
# service configs
for config in request.service_configs:
grpcutils.service_configuration(session, config)
# service file configs
for config in request.service_file_configs:
session.services.set_service_file(
config.node_id, config.service, config.file, config.data
)
# create links
grpcutils.create_links(session, request.links)
@ -1172,11 +1182,8 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
"""
logging.debug("set node service: %s", request)
session = self.get_session(request.session_id, context)
session.services.set_service(request.node_id, request.service)
service = session.services.get_service(request.node_id, request.service)
service.startup = tuple(request.startup)
service.validate = tuple(request.validate)
service.shutdown = tuple(request.shutdown)
config = request.config
grpcutils.service_configuration(session, config)
return core_pb2.SetNodeServiceResponse(result=True)
def SetNodeServiceFile(self, request, context):
@ -1191,8 +1198,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
"""
logging.debug("set node service file: %s", request)
session = self.get_session(request.session_id, context)
config = request.config
session.services.set_service_file(
request.node_id, request.service, request.file, request.data
config.node_id, config.service, config.file, config.data
)
return core_pb2.SetNodeServiceFileResponse(result=True)

View file

@ -144,6 +144,8 @@ message StartSessionRequest {
repeated WlanConfig wlan_configs = 7;
repeated EmaneModelConfig emane_model_configs = 8;
repeated MobilityConfig mobility_configs = 9;
repeated ServiceConfig service_configs = 10;
repeated ServiceFileConfig service_file_configs = 11;
}
message StartSessionResponse {
@ -554,11 +556,7 @@ message GetNodeServiceFileResponse {
message SetNodeServiceRequest {
int32 session_id = 1;
int32 node_id = 2;
string service = 3;
repeated string startup = 4;
repeated string validate = 5;
repeated string shutdown = 6;
ServiceConfig config = 2;
}
message SetNodeServiceResponse {
@ -567,10 +565,7 @@ message SetNodeServiceResponse {
message SetNodeServiceFileRequest {
int32 session_id = 1;
int32 node_id = 2;
string service = 3;
string file = 4;
string data = 5;
ServiceFileConfig config = 2;
}
message SetNodeServiceFileResponse {
@ -718,6 +713,21 @@ message EmaneModelConfig {
map<string, string> config = 4;
}
message ServiceConfig {
int32 node_id = 1;
string service = 2;
repeated string startup = 3;
repeated string validate = 4;
repeated string shutdown = 5;
}
message ServiceFileConfig {
int32 node_id = 1;
string service = 2;
string file = 3;
string data = 4;
}
message MessageType {
enum Enum {
NONE = 0;

View file

@ -27,7 +27,6 @@ class TestGrpc:
# given
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
nodes = []
position = core_pb2.Position(x=50, y=100)
node_one = core_pb2.Node(id=1, position=position, model="PC")
position = core_pb2.Position(x=100, y=100)
@ -36,8 +35,7 @@ class TestGrpc:
wlan_node = core_pb2.Node(
id=3, type=NodeTypes.WIRELESS_LAN.value, position=position
)
nodes.extend([node_one, node_two, wlan_node])
links = []
nodes = [node_one, node_two, wlan_node]
interface_helper = InterfaceHelper(ip4_prefix="10.83.0.0/16")
interface_one = interface_helper.create_interface(node_one.id, 0)
interface_two = interface_helper.create_interface(node_two.id, 0)
@ -48,12 +46,11 @@ class TestGrpc:
interface_one=interface_one,
interface_two=interface_two,
)
links.append(link)
hooks = []
links = [link]
hook = core_pb2.Hook(
state=core_pb2.SessionState.RUNTIME, file="echo.sh", data="echo hello"
)
hooks.append(hook)
hooks = [hook]
location_x = 5
location_y = 10
location_z = 15
@ -73,7 +70,6 @@ class TestGrpc:
emane_config_key = "platform_id_start"
emane_config_value = "2"
emane_config = {emane_config_key: emane_config_value}
model_configs = []
model_node_id = 20
model_config_key = "bandwidth"
model_config_value = "500000"
@ -83,21 +79,30 @@ class TestGrpc:
model=EmaneIeee80211abgModel.name,
config={model_config_key: model_config_value},
)
model_configs.append(model_config)
wlan_configs = []
model_configs = [model_config]
wlan_config_key = "range"
wlan_config_value = "333"
wlan_config = core_pb2.WlanConfig(
node_id=wlan_node.id, config={wlan_config_key: wlan_config_value}
)
wlan_configs.append(wlan_config)
wlan_configs = [wlan_config]
mobility_config_key = "refresh_ms"
mobility_config_value = "60"
mobility_configs = []
mobility_config = core_pb2.MobilityConfig(
node_id=wlan_node.id, config={mobility_config_key: mobility_config_value}
)
mobility_configs.append(mobility_config)
mobility_configs = [mobility_config]
service_config = core_pb2.ServiceConfig(
node_id=node_one.id, service="DefaultRoute", validate=["echo hello"]
)
service_configs = [service_config]
service_file_config = core_pb2.ServiceFileConfig(
node_id=node_one.id,
service="DefaultRoute",
file="defaultroute.sh",
data="echo hello",
)
service_file_configs = [service_file_config]
# when
with patch.object(CoreXmlWriter, "write"):
@ -112,6 +117,8 @@ class TestGrpc:
model_configs,
wlan_configs,
mobility_configs,
service_configs,
service_file_configs,
)
# then
@ -139,6 +146,14 @@ class TestGrpc:
model_node_id, EmaneIeee80211abgModel.name
)
assert set_model_config[model_config_key] == model_config_value
service = session.services.get_service(
node_one.id, service_config.service, default_service=True
)
assert service.validate == tuple(service_config.validate)
service_file = session.services.get_service_file(
node_one, service_file_config.service, service_file_config.file
)
assert service_file.data == service_file_config.data
@pytest.mark.parametrize("session_id", [None, 6013])
def test_create_session(self, grpc_server, session_id):