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

View file

@ -1,7 +1,6 @@
"""
emane configuration
"""
import logging
import tkinter as tk
import webbrowser
@ -11,271 +10,122 @@ from coretk.dialogs.dialog import Dialog
from coretk.images import ImageEnum, Images
from coretk.widgets import ConfigFrame
PAD_X = 2
PAD_Y = 2
PAD = 5
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):
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.canvas_node = canvas_node
self.node = canvas_node.core_node
self.radiovar = tk.IntVar()
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
self.emane_models = None
self.emane_dialog = Dialog(self, app, "emane configuration", modal=False)
self.emane_model_dialog = None
self.emane_model_combobox = None
# draw
self.node_name_and_image()
self.emane_configuration()
self.draw_ip_subnets()
self.emane_options()
def draw(self):
self.top.columnconfigure(0, weight=1)
self.draw_emane_configuration()
self.draw_emane_models()
self.draw_emane_buttons()
self.draw_apply_and_cancel()
self.emane_config_frame = None
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):
def draw_emane_configuration(self):
"""
draw the main frame for emane configuration
:return: nothing
"""
# draw label
lbl = ttk.Label(self.top, text="Emane")
lbl.grid(row=1, column=0)
# main frame that has emane wiki, a short description, emane models and the configure buttons
f = ttk.Frame(self.top)
f.columnconfigure(0, weight=1)
label = ttk.Label(
self.top,
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",
)
label.grid(sticky="ew", pady=PAD)
image = Images.get(ImageEnum.EDITNODE, 16)
b = ttk.Button(
f,
button = ttk.Button(
self.top,
image=image,
text="EMANE Wiki",
compound=tk.RIGHT,
@ -283,55 +133,99 @@ class EmaneConfiguration(Dialog):
"https://github.com/adjacentlink/emane/wiki"
),
)
b.image = image
b.grid(row=0, column=0, sticky="w")
button.image = image
button.grid(sticky="ew", pady=PAD)
lbl = ttk.Label(
f,
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",
def draw_emane_models(self):
"""
create a combobox that has all the known emane models
: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")
lbl.grid(row=2, column=0, sticky="w")
def draw_emane_buttons(self):
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)
self.draw_option_buttons(f)
image = Images.get(ImageEnum.EDITNODE, 16)
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")
def draw_ip_subnets(self):
self.draw_text_label_and_entry(self.top, "IPv4 subnet", "")
self.draw_text_label_and_entry(self.top, "IPv6 subnet", "")
def emane_options(self):
"""
create wireless node options
: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()
image = Images.get(ImageEnum.EDITNODE, 16)
button = ttk.Button(
frame,
text="EMANE options",
image=image,
compound=tk.RIGHT,
command=self.click_emane_config,
)
button.image = image
button.grid(row=0, column=1, sticky="ew")
def draw_apply_and_cancel(self):
f = ttk.Frame(self.top)
f.columnconfigure(0, weight=1)
f.columnconfigure(1, weight=1)
b = ttk.Button(f, text="Apply", command=self.apply)
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")
frame = ttk.Frame(self.top)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
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
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(
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.core_pb2 import NodeType
from coretk.canvastooltip import CanvasTooltip
from coretk.dialogs.emaneconfig import EmaneConfigDialog
from coretk.dialogs.mobilityconfig import MobilityConfigDialog
from coretk.dialogs.nodeconfig import NodeConfigDialog
from coretk.dialogs.wlanconfig import WlanConfigDialog
@ -77,6 +78,10 @@ class CanvasGraph(tk.Canvas):
context.add_command(
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="Create link to", state=tk.DISABLED)
context.add_command(label="Assign to", state=tk.DISABLED)
@ -711,3 +716,8 @@ class CanvasNode:
self.canvas.context = None
dialog = MobilityConfigDialog(self.app, self.app, self)
dialog.show()
def show_emane_config(self):
self.canvas.context = None
dialog = EmaneConfigDialog(self.app, self.app, self)
dialog.show()