small cleanup to emane config dialog, fixed default service storage to just use names

This commit is contained in:
Blake Harnden 2019-11-21 14:41:05 -08:00
parent 471c5eb7e1
commit b983a09ae7
4 changed files with 209 additions and 314 deletions

View file

@ -50,6 +50,7 @@ class CoreClient:
self.master = app.master self.master = app.master
self.interface_helper = None self.interface_helper = None
self.services = {} self.services = {}
self.emane_models = []
self.observer = None self.observer = None
# loaded configuration data # loaded configuration data
@ -70,6 +71,7 @@ class CoreClient:
self.interfaces_manager = InterfaceManager() self.interfaces_manager = InterfaceManager()
self.wlan_configs = {} self.wlan_configs = {}
self.mobility_configs = {} self.mobility_configs = {}
self.emane_model_configs = {}
self.emaneconfig_management = EmaneModelNodeConfig(app) self.emaneconfig_management = EmaneModelNodeConfig(app)
self.emane_config = None self.emane_config = None
self.serviceconfig_manager = ServiceNodeConfig(app) self.serviceconfig_manager = ServiceNodeConfig(app)
@ -145,6 +147,10 @@ class CoreClient:
self.state = session.state self.state = session.state
self.client.events(self.session_id, self.handle_events) self.client.events(self.session_id, self.handle_events)
# get emane models
response = self.client.get_emane_models(self.session_id)
self.emane_models = response.models
# get hooks # get hooks
response = self.client.get_hooks(self.session_id) response = self.client.get_hooks(self.session_id)
logging.info("joined session hooks: %s", response) logging.info("joined session hooks: %s", response)
@ -240,8 +246,8 @@ class CoreClient:
# get service information # get service information
response = self.client.get_services() response = self.client.get_services()
for service in response.services: for service in response.services:
group_services = self.services.setdefault(service.group, []) group_services = self.services.setdefault(service.group, set())
group_services.append(service) group_services.add(service.name)
# if there are no sessions, create a new session, else join a session # if there are no sessions, create a new session, else join a session
response = self.client.get_sessions() response = self.client.get_sessions()
@ -443,6 +449,9 @@ class CoreClient:
image = None image = None
if NodeUtils.is_image_node(node_type): if NodeUtils.is_image_node(node_type):
image = "ubuntu:latest" image = "ubuntu:latest"
emane = None
if node_type == core_pb2.NodeType.EMANE:
emane = self.emane_models[0]
node = core_pb2.Node( node = core_pb2.Node(
id=node_id, id=node_id,
type=node_type, type=node_type,
@ -450,6 +459,7 @@ class CoreClient:
model=model, model=model,
position=position, position=position,
image=image, image=image,
emane=emane,
) )
# set default emane configuration for emane node # set default emane configuration for emane node
@ -571,25 +581,6 @@ class CoreClient:
if interface_two is not None: if interface_two is not None:
self.interface_to_edge[(node_two.id, interface_two.id)] = token self.interface_to_edge[(node_two.id, interface_two.id)] = token
# emane setup
# TODO: determine if this is needed
if (
node_one.type == core_pb2.NodeType.EMANE
and node_two.type == core_pb2.NodeType.DEFAULT
):
if node_two.model == "mdr":
self.emaneconfig_management.set_default_for_mdr(
node_one.node_id, node_two.node_id, interface_two.id
)
elif (
node_two.type == core_pb2.NodeType.EMANE
and node_one.type == core_pb2.NodeType.DEFAULT
):
if node_one.model == "mdr":
self.emaneconfig_management.set_default_for_mdr(
node_two.node_id, node_one.node_id, interface_one.id
)
link = core_pb2.Link( link = core_pb2.Link(
type=core_pb2.LinkType.WIRED, type=core_pb2.LinkType.WIRED,
node_one_id=node_one.id, node_one_id=node_one.id,

View file

@ -1,7 +1,6 @@
""" """
emane configuration emane configuration
""" """
import logging import logging
import tkinter as tk import tkinter as tk
import webbrowser import webbrowser
@ -11,271 +10,122 @@ from coretk.dialogs.dialog import Dialog
from coretk.images import ImageEnum, Images from coretk.images import ImageEnum, Images
from coretk.widgets import ConfigFrame from coretk.widgets import ConfigFrame
PAD_X = 2 PAD = 5
PAD_Y = 2
class EmaneConfiguration(Dialog): class GlobalEmaneDialog(Dialog):
def __init__(self, master, app):
super().__init__(master, app, "EMANE Configuration", modal=True)
self.config_frame = None
self.draw()
def draw(self):
self.top.columnconfigure(0, weight=1)
self.top.rowconfigure(0, weight=1)
self.config_frame = ConfigFrame(
self.top, self.app, self.app.core.emane_config, borderwidth=0
)
self.config_frame.draw_config()
self.config_frame.grid(sticky="nsew", pady=PAD)
self.draw_buttons()
def draw_buttons(self):
frame = ttk.Frame(self.top)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = ttk.Button(frame, text="Apply", command=self.click_apply)
button.grid(row=0, column=0, sticky="ew", padx=PAD)
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
def click_apply(self):
self.config_frame.parse_config()
self.destroy()
class EmaneModelDialog(Dialog):
def __init__(self, master, app, node, model):
super().__init__(master, app, f"{node.name} {model} Configuration", modal=True)
self.node = node
self.model = f"emane_{model}"
self.config_frame = None
session_id = self.app.core.session_id
response = self.app.core.client.get_emane_model_config(
session_id, self.node.id, self.model
)
self.config = response.config
self.draw()
def draw(self):
self.top.columnconfigure(0, weight=1)
self.top.rowconfigure(0, weight=1)
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_buttons()
def draw_buttons(self):
frame = ttk.Frame(self.top)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = ttk.Button(frame, text="Apply", command=self.click_apply)
button.grid(row=0, column=0, sticky="ew", padx=PAD)
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
def click_apply(self):
self.config_frame.parse_config()
self.app.core.emaneconfig_management.set_custom_emane_cloud_config(
self.node.id, self.model
)
self.destroy()
class EmaneConfigDialog(Dialog):
def __init__(self, master, app, canvas_node): def __init__(self, master, app, canvas_node):
super().__init__(master, app, "emane configuration", modal=False) super().__init__(
master, app, f"{canvas_node.core_node.name} EMANE Configuration", modal=True
)
self.app = app self.app = app
self.canvas_node = canvas_node self.canvas_node = canvas_node
self.node = canvas_node.core_node self.node = canvas_node.core_node
self.radiovar = tk.IntVar() self.radiovar = tk.IntVar()
self.radiovar.set(1) self.radiovar.set(1)
self.columnconfigure(0, weight=1) self.emane_models = [x.split("_")[1] for x in self.app.core.emane_models]
emane_model = None
if self.emane_models:
emane_model = self.emane_models[0]
self.emane_model = tk.StringVar(value=emane_model)
self.emane_model_button = None
self.draw()
# list(string) of emane models def draw(self):
self.emane_models = None self.top.columnconfigure(0, weight=1)
self.draw_emane_configuration()
self.emane_dialog = Dialog(self, app, "emane configuration", modal=False) self.draw_emane_models()
self.emane_model_dialog = None self.draw_emane_buttons()
self.emane_model_combobox = None
# draw
self.node_name_and_image()
self.emane_configuration()
self.draw_ip_subnets()
self.emane_options()
self.draw_apply_and_cancel() self.draw_apply_and_cancel()
self.emane_config_frame = None def draw_emane_configuration(self):
self.options = app.core.emane_config
self.model_options = None
self.model_config_frame = None
def create_text_variable(self, val):
"""
create a string variable for convenience
:param str val: entry text
:return: nothing
"""
var = tk.StringVar()
var.set(val)
return var
def choose_core(self):
logging.info("not implemented")
def node_name_and_image(self):
f = ttk.Frame(self.top)
lbl = ttk.Label(f, text="Node name:")
lbl.grid(row=0, column=0, padx=2, pady=2)
e = ttk.Entry(f, textvariable=self.create_text_variable(""))
e.grid(row=0, column=1, padx=2, pady=2)
cbb = ttk.Combobox(f, values=["(none)", "core1", "core2"], state="readonly")
cbb.current(0)
cbb.grid(row=0, column=2, padx=2, pady=2)
b = ttk.Button(f, image=self.canvas_node.image)
b.grid(row=0, column=3, padx=2, pady=2)
f.grid(row=0, column=0, sticky="nsew")
def save_emane_option(self):
self.emane_config_frame.parse_config()
self.emane_dialog.destroy()
def draw_emane_options(self):
if not self.emane_dialog.winfo_exists():
self.emane_dialog = Dialog(
self, self.app, "emane configuration", modal=False
)
if self.options is None:
session_id = self.app.core.session_id
response = self.app.core.client.get_emane_config(session_id)
logging.info("emane config: %s", response)
self.options = response.config
self.emane_dialog.top.columnconfigure(0, weight=1)
self.emane_dialog.top.rowconfigure(0, weight=1)
self.emane_config_frame = ConfigFrame(
self.emane_dialog.top, self.app, config=self.options
)
self.emane_config_frame.draw_config()
self.emane_config_frame.grid(sticky="nsew")
frame = ttk.Frame(self.emane_dialog.top)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
b1 = ttk.Button(frame, text="Appy", command=self.save_emane_option)
b1.grid(row=0, column=0, sticky="ew")
b2 = ttk.Button(frame, text="Cancel", command=self.emane_dialog.destroy)
b2.grid(row=0, column=1, sticky="ew")
self.emane_dialog.show()
def save_emane_model_options(self):
"""
configure the node's emane model on the fly
:return: nothing
"""
# get model name
model_name = self.emane_models[self.emane_model_combobox.current()]
# parse configuration
config = self.model_config_frame.parse_config()
# add string emane_ infront for grpc call
response = self.app.core.client.set_emane_model_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.node.id, response
)
# store the change locally
self.app.core.emaneconfig_management.set_custom_emane_cloud_config(
self.node.id, f"emane_{model_name}"
)
self.emane_model_dialog.destroy()
def draw_model_options(self):
"""
draw emane model configuration
:return: nothing
"""
# get model name
model_name = self.emane_models[self.emane_model_combobox.current()]
# create the dialog and the necessry widget
if not self.emane_model_dialog or not self.emane_model_dialog.winfo_exists():
self.emane_model_dialog = Dialog(
self, self.app, f"{model_name} configuration", modal=False
)
self.emane_model_dialog.top.columnconfigure(0, weight=1)
self.emane_model_dialog.top.rowconfigure(0, weight=1)
# query for configurations
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.node.id, f"emane_{model_name}"
)
logging.info("emane model config %s", response)
self.model_options = response.config
self.model_config_frame = ConfigFrame(
self.emane_model_dialog.top, self.app, config=self.model_options
)
self.model_config_frame.grid(sticky="nsew")
self.model_config_frame.draw_config()
frame = ttk.Frame(self.emane_model_dialog.top)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
b1 = ttk.Button(frame, text="Apply", command=self.save_emane_model_options)
b1.grid(row=0, column=0, sticky="ew")
b2 = ttk.Button(frame, text="Cancel", command=self.emane_model_dialog.destroy)
b2.grid(row=0, column=1, sticky="ew")
self.emane_model_dialog.show()
def draw_option_buttons(self, parent):
f = ttk.Frame(parent)
f.grid(row=4, column=0, sticky="nsew")
f.columnconfigure(0, weight=1)
f.columnconfigure(1, weight=1)
image = Images.get(ImageEnum.EDITNODE, 16)
b = ttk.Button(
f,
text=self.emane_models[0] + " options",
image=image,
compound=tk.RIGHT,
command=self.draw_model_options,
)
b.image = image
b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew")
image = Images.get(ImageEnum.EDITNODE, 16)
b = ttk.Button(
f,
text="EMANE options",
image=image,
compound=tk.RIGHT,
command=self.draw_emane_options,
)
b.image = image
b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew")
def combobox_select(self, event):
"""
update emane model options button
:param event:
:return: nothing
"""
# get model name
model_name = self.emane_models[self.emane_model_combobox.current()]
# get the button and configure button text
config_frame = self.grid_slaves(row=2, column=0)[0]
option_button_frame = config_frame.grid_slaves(row=4, column=0)[0]
b = option_button_frame.grid_slaves(row=0, column=0)[0]
b.config(text=model_name + " options")
def draw_emane_models(self, parent):
"""
create a combobox that has all the known emane models
:param parent: parent
:return: nothing
"""
# query for all the known model names
session_id = self.app.core.session_id
response = self.app.core.client.get_emane_models(session_id)
self.emane_models = [x.split("_")[1] for x in response.models]
# create combo box and its binding
f = ttk.Frame(parent)
self.emane_model_combobox = ttk.Combobox(
f, values=self.emane_models, state="readonly"
)
self.emane_model_combobox.grid()
self.emane_model_combobox.current(0)
self.emane_model_combobox.bind("<<ComboboxSelected>>", self.combobox_select)
f.grid(row=3, column=0, sticky="ew")
def draw_text_label_and_entry(self, parent, label_text, entry_text):
"""
draw a label and an entry on a single row
:return: nothing
"""
var = tk.StringVar()
var.set(entry_text)
f = ttk.Frame(parent)
lbl = ttk.Label(f, text=label_text)
lbl.grid(row=0, column=0)
e = ttk.Entry(f, textvariable=var)
e.grid(row=0, column=1)
f.grid(stick=tk.W, padx=2, pady=2)
def emane_configuration(self):
""" """
draw the main frame for emane configuration draw the main frame for emane configuration
:return: nothing :return: nothing
""" """
# draw label label = ttk.Label(
lbl = ttk.Label(self.top, text="Emane") self.top,
lbl.grid(row=1, column=0) text="The EMANE emulation system provides more complex wireless radio emulation "
"\nusing pluggable MAC and PHY modules. Refer to the wiki for configuration option details",
# main frame that has emane wiki, a short description, emane models and the configure buttons )
f = ttk.Frame(self.top) label.grid(sticky="ew", pady=PAD)
f.columnconfigure(0, weight=1)
image = Images.get(ImageEnum.EDITNODE, 16) image = Images.get(ImageEnum.EDITNODE, 16)
b = ttk.Button( button = ttk.Button(
f, self.top,
image=image, image=image,
text="EMANE Wiki", text="EMANE Wiki",
compound=tk.RIGHT, compound=tk.RIGHT,
@ -283,55 +133,99 @@ class EmaneConfiguration(Dialog):
"https://github.com/adjacentlink/emane/wiki" "https://github.com/adjacentlink/emane/wiki"
), ),
) )
b.image = image button.image = image
b.grid(row=0, column=0, sticky="w") button.grid(sticky="ew", pady=PAD)
lbl = ttk.Label( def draw_emane_models(self):
f, """
text="The EMANE emulation system provides more complex wireless radio emulation " create a combobox that has all the known emane models
"\nusing pluggable MAC and PHY modules. Refer to the wiki for configuration option details",
:return: nothing
"""
frame = ttk.Frame(self.top)
frame.grid(sticky="ew", pady=PAD)
frame.columnconfigure(1, weight=1)
label = ttk.Label(frame, text="Model")
label.grid(row=0, column=0, sticky="w")
# create combo box and its binding
combobox = ttk.Combobox(
frame,
textvariable=self.emane_model,
values=self.emane_models,
state="readonly",
) )
lbl.grid(row=1, column=0, sticky="nsew") combobox.grid(row=0, column=1, sticky="ew")
combobox.bind("<<ComboboxSelected>>", self.emane_model_change)
lbl = ttk.Label(f, text="EMANE Models") def draw_emane_buttons(self):
lbl.grid(row=2, column=0, sticky="w") frame = ttk.Frame(self.top)
frame.grid(sticky="ew", pady=PAD)
for i in range(2):
frame.columnconfigure(i, weight=1)
self.draw_emane_models(f) image = Images.get(ImageEnum.EDITNODE, 16)
self.draw_option_buttons(f) self.emane_model_button = ttk.Button(
frame,
text=f"{self.emane_model.get()} options",
image=image,
compound=tk.RIGHT,
command=self.click_model_config,
)
self.emane_model_button.image = image
self.emane_model_button.grid(row=0, column=0, padx=PAD, sticky="ew")
f.grid(row=2, column=0, sticky="nsew") image = Images.get(ImageEnum.EDITNODE, 16)
button = ttk.Button(
def draw_ip_subnets(self): frame,
self.draw_text_label_and_entry(self.top, "IPv4 subnet", "") text="EMANE options",
self.draw_text_label_and_entry(self.top, "IPv6 subnet", "") image=image,
compound=tk.RIGHT,
def emane_options(self): command=self.click_emane_config,
""" )
create wireless node options button.image = image
button.grid(row=0, column=1, sticky="ew")
:return:
"""
f = ttk.Frame(self.top)
f.columnconfigure(0, weight=1)
f.columnconfigure(1, weight=1)
b = ttk.Button(f, text="Link to all routers")
b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew")
b = ttk.Button(f, text="Choose WLAN members")
b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew")
f.grid(row=5, column=0, sticky="nsew")
def apply(self):
# save emane configuration
self.app.core.emane_config = self.options
self.destroy()
def draw_apply_and_cancel(self): def draw_apply_and_cancel(self):
f = ttk.Frame(self.top) frame = ttk.Frame(self.top)
f.columnconfigure(0, weight=1) frame.grid(sticky="ew")
f.columnconfigure(1, weight=1) for i in range(2):
b = ttk.Button(f, text="Apply", command=self.apply) frame.columnconfigure(i, weight=1)
b.grid(row=0, column=0, padx=10, pady=2, sticky="nsew")
b = ttk.Button(f, text="Cancel", command=self.destroy)
b.grid(row=0, column=1, padx=10, pady=2, sticky="nsew")
f.grid(sticky="nsew") button = ttk.Button(frame, text="Apply", command=self.click_apply)
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, sticky="ew")
def click_emane_config(self):
dialog = GlobalEmaneDialog(self, self.app)
dialog.show()
def click_model_config(self):
"""
draw emane model configuration
:return: nothing
"""
model_name = self.emane_model.get()
logging.info("configuring emane model: %s", model_name)
dialog = EmaneModelDialog(
self, self.app, self.canvas_node.core_node, model_name
)
dialog.show()
def emane_model_change(self, event):
"""
update emane model options button
:param event:
:return: nothing
"""
model_name = self.emane_model.get()
self.emane_model_button.config(text=f"{model_name} options")
def click_apply(self):
self.node.emane = f"emane_{self.emane_model.get()}"
self.destroy()

View file

@ -28,7 +28,7 @@ class EmaneModelNodeConfig:
""" """
session_id = self.app.core.session_id session_id = self.app.core.session_id
client = self.app.core.client client = self.app.core.client
default_emane_model = client.get_emane_models(session_id).models[0] default_emane_model = self.app.core.emane_models[0]
response = client.get_emane_model_config( response = client.get_emane_model_config(
session_id, node_id, default_emane_model session_id, node_id, default_emane_model
) )

View file

@ -7,6 +7,7 @@ from PIL import ImageTk
from core.api.grpc import core_pb2 from core.api.grpc import core_pb2
from core.api.grpc.core_pb2 import NodeType from core.api.grpc.core_pb2 import NodeType
from coretk.canvastooltip import CanvasTooltip from coretk.canvastooltip import CanvasTooltip
from coretk.dialogs.emaneconfig import EmaneConfigDialog
from coretk.dialogs.mobilityconfig import MobilityConfigDialog from coretk.dialogs.mobilityconfig import MobilityConfigDialog
from coretk.dialogs.nodeconfig import NodeConfigDialog from coretk.dialogs.nodeconfig import NodeConfigDialog
from coretk.dialogs.wlanconfig import WlanConfigDialog from coretk.dialogs.wlanconfig import WlanConfigDialog
@ -77,6 +78,10 @@ class CanvasGraph(tk.Canvas):
context.add_command( context.add_command(
label="Mobility Config", command=canvas_node.show_mobility_config label="Mobility Config", command=canvas_node.show_mobility_config
) )
if node.type == NodeType.EMANE:
context.add_command(
label="EMANE Config", command=canvas_node.show_emane_config
)
context.add_command(label="Select adjacent", state=tk.DISABLED) context.add_command(label="Select adjacent", state=tk.DISABLED)
context.add_command(label="Create link to", 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="Assign to", state=tk.DISABLED)
@ -711,3 +716,8 @@ class CanvasNode:
self.canvas.context = None self.canvas.context = None
dialog = MobilityConfigDialog(self.app, self.app, self) dialog = MobilityConfigDialog(self.app, self.app, self)
dialog.show() dialog.show()
def show_emane_config(self):
self.canvas.context = None
dialog = EmaneConfigDialog(self.app, self.app, self)
dialog.show()