Merge branch 'coretk' into coretk-config

This commit is contained in:
Huy Pham 2019-11-21 12:34:28 -08:00
commit a4055f84bd
8 changed files with 58 additions and 320 deletions

View file

@ -8,7 +8,6 @@ from core.api.grpc import client, core_pb2
from coretk.dialogs.sessions import SessionsDialog
from coretk.emaneodelnodeconfig import EmaneModelNodeConfig
from coretk.interface import InterfaceManager
from coretk.mobilitynodeconfig import MobilityNodeConfig
from coretk.nodeutils import NodeDraw, NodeUtils
from coretk.servicefileconfig import ServiceFileConfig
from coretk.servicenodeconfig import ServiceNodeConfig
@ -70,7 +69,7 @@ class CoreClient:
self.preexisting = set()
self.interfaces_manager = InterfaceManager()
self.wlan_configs = {}
self.mobilityconfig_management = MobilityNodeConfig()
self.mobility_configs = {}
self.emaneconfig_management = EmaneModelNodeConfig(app)
self.emane_config = None
self.serviceconfig_manager = ServiceNodeConfig(app)
@ -136,7 +135,7 @@ class CoreClient:
self.links.clear()
self.hooks.clear()
self.wlan_configs.clear()
self.mobilityconfig_management.configurations.clear()
self.mobility_configs.clear()
self.emane_config = None
# get session data
@ -164,8 +163,7 @@ class CoreClient:
logging.debug("mobility configs: %s", response)
for node_id in response.configs:
node_config = response.configs[node_id].config
config = {x: node_config[x].value for x in node_config}
self.mobilityconfig_management.configurations[node_id] = config
self.mobility_configs[node_id] = node_config
# get emane config
response = self.client.get_emane_config(self.session_id)
@ -454,9 +452,6 @@ class CoreClient:
image=image,
)
# set default configuration for wireless node
self.mobilityconfig_management.set_default_configuration(node_type, node_id)
# set default emane configuration for emane node
if node_type == core_pb2.NodeType.EMANE:
self.emaneconfig_management.set_default_config(node_id)
@ -519,8 +514,8 @@ class CoreClient:
# delete any mobility configuration, wlan configuration
for i in node_ids:
if i in self.mobilityconfig_management.configurations:
self.mobilityconfig_management.configurations.pop(i)
if i in self.mobility_configs:
del self.mobility_configs[i]
if i in self.wlan_configs:
del self.wlan_configs[i]
@ -615,11 +610,10 @@ class CoreClient:
def get_mobility_configs_proto(self):
configs = []
mobility_configs = self.mobilityconfig_management.configurations
for node_id in mobility_configs:
config = mobility_configs[node_id]
config_proto = core_pb2.MobilityConfig(node_id=node_id, config=config)
configs.append(config_proto)
for node_id, config in self.mobility_configs.items():
config = {x: config[x].value for x in config}
mobility_config = core_pb2.MobilityConfig(node_id=node_id, config=config)
configs.append(mobility_config)
return configs
def get_emane_model_configs_proto(self):
@ -676,5 +670,11 @@ class CoreClient:
if not config:
response = self.client.get_wlan_config(self.session_id, node_id)
config = response.config
self.wlan_configs[node_id] = config
return config
def get_mobility_config(self, node_id):
config = self.mobility_configs.get(node_id)
if not config:
response = self.client.get_mobility_config(self.session_id, node_id)
config = response.config
return config

View file

@ -1,236 +1,48 @@
"""
mobility configuration
"""
import logging
import tkinter as tk
from tkinter import filedialog, ttk
from tkinter import ttk
from coretk import appconfig
from coretk.dialogs.dialog import Dialog
from coretk.widgets import ConfigFrame
PAD = 5
class MobilityConfigDialog(Dialog):
def __init__(self, master, app, canvas_node):
"""
create an instance of mobility configuration
:param app: core application
:param root.master master:
"""
super().__init__(master, app, "ns2script configuration", modal=True)
super().__init__(
master,
app,
f"{canvas_node.core_node.name} Mobility 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[
self.node.id
]
self.config_frame = None
self.config = self.app.core.get_mobility_config(self.node.id)
self.draw()
self.mobility_script_parameters()
self.ns2script_options()
self.loop = "On"
def draw(self):
self.top.columnconfigure(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_apply_buttons()
def create_string_var(self, val):
"""
create string variable for entry widget
def draw_apply_buttons(self):
frame = ttk.Frame(self.top)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
:return: nothing
"""
var = tk.StringVar()
var.set(val)
return var
button = ttk.Button(frame, text="Apply", command=self.click_apply)
button.grid(row=0, column=0, padx=PAD, sticky="ew")
def open_file(self, entry):
filename = filedialog.askopenfilename(
initialdir=str(appconfig.MOBILITY_PATH), title="Open"
)
if filename:
entry.delete(0, tk.END)
entry.insert(0, filename)
def set_loop_value(self, value):
"""
set loop value when user changes the option
:param value:
:return:
"""
self.loop = value
def create_label_entry_filebrowser(
self, parent_frame, text_label, entry_text, filebrowser=False
):
f = ttk.Frame(parent_frame)
lbl = ttk.Label(f, text=text_label)
lbl.grid(padx=3, pady=3)
# f.grid()
e = ttk.Entry(f, textvariable=self.create_string_var(entry_text))
e.grid(row=0, column=1, padx=3, pady=3)
if filebrowser:
b = ttk.Button(f, text="...", command=lambda: self.open_file(e))
b.grid(row=0, column=2, padx=3, pady=3)
f.grid(sticky=tk.E)
def mobility_script_parameters(self):
lbl = ttk.Label(self.top, text="node ns2script")
lbl.grid(sticky="ew")
sb = ttk.Scrollbar(self.top, orient=tk.VERTICAL)
sb.grid(row=1, column=1, sticky="ns")
f = ttk.Frame(self.top)
lbl = ttk.Label(f, text="ns-2 Mobility Scripts Parameters")
lbl.grid(row=0, column=0, sticky=tk.W)
f1 = tk.Canvas(
f,
yscrollcommand=sb.set,
bg="#d9d9d9",
relief=tk.RAISED,
highlightbackground="#b3b3b3",
highlightcolor="#b3b3b3",
highlightthickness=0.5,
bd=0,
)
self.create_label_entry_filebrowser(
f1, "mobility script file", self.node_config["file"], filebrowser=True
)
self.create_label_entry_filebrowser(
f1, "Refresh time (ms)", self.node_config["refresh_ms"]
)
# f12 = ttk.Frame(f1)
#
# lbl = ttk.Label(f12, text="Refresh time (ms)")
# lbl.grid()
#
# e = ttk.Entry(f12, textvariable=self.create_string_var("50"))
# e.grid(row=0, column=1)
# f12.grid()
f13 = ttk.Frame(f1)
lbl = ttk.Label(f13, text="loop")
lbl.grid()
om = ttk.OptionMenu(
f13, self.create_string_var("On"), "On", "Off", command=self.set_loop_value
)
om.grid(row=0, column=1)
f13.grid(sticky=tk.E)
self.create_label_entry_filebrowser(
f1, "auto-start seconds (0.0 for runtime)", self.node_config["autostart"]
)
# f14 = ttk.Frame(f1)
#
# lbl = ttk.Label(f14, text="auto-start seconds (0.0 for runtime)")
# lbl.grid()
#
# e = ttk.Entry(f14, textvariable=self.create_string_var(""))
# e.grid(row=0, column=1)
#
# f14.grid()
self.create_label_entry_filebrowser(
f1, "node mapping (optional, e.g. 0:1, 1:2, 2:3)", self.node_config["map"]
)
# f15 = ttk.Frame(f1)
#
# lbl = ttk.Label(f15, text="node mapping (optional, e.g. 0:1, 1:2, 2:3)")
# lbl.grid()
#
# e = ttk.Entry(f15, textvariable=self.create_string_var(""))
# e.grid(row=0, column=1)
#
# f15.grid()
self.create_label_entry_filebrowser(
f1,
"script file to run upon start",
self.node_config["script_start"],
filebrowser=True,
)
self.create_label_entry_filebrowser(
f1,
"script file to run upon pause",
self.node_config["script_pause"],
filebrowser=True,
)
self.create_label_entry_filebrowser(
f1,
"script file to run upon stop",
self.node_config["script_stop"],
filebrowser=True,
)
f1.grid()
sb.config(command=f1.yview)
f.grid(row=1, column=0)
def ns2script_apply(self):
"""
:return:
"""
config_frame = self.grid_slaves(row=1, column=0)[0]
canvas = config_frame.grid_slaves(row=1, column=0)[0]
file = (
canvas.grid_slaves(row=0, column=0)[0].grid_slaves(row=0, column=1)[0].get()
)
refresh_time = (
canvas.grid_slaves(row=1, column=0)[0].grid_slaves(row=0, column=1)[0].get()
)
auto_start_seconds = (
canvas.grid_slaves(row=3, column=0)[0].grid_slaves(row=0, column=1)[0].get()
)
node_mapping = (
canvas.grid_slaves(row=4, column=0)[0].grid_slaves(row=0, column=1)[0].get()
)
file_upon_start = (
canvas.grid_slaves(row=5, column=0)[0].grid_slaves(row=0, column=1)[0].get()
)
file_upon_pause = (
canvas.grid_slaves(row=6, column=0)[0].grid_slaves(row=0, column=1)[0].get()
)
file_upon_stop = (
canvas.grid_slaves(row=7, column=0)[0].grid_slaves(row=0, column=1)[0].get()
)
# print("mobility script file: ", file)
# print("refresh time: ", refresh_time)
# print("auto start seconds: ", auto_start_seconds)
# print("node mapping: ", node_mapping)
# print("script file to run upon start: ", file_upon_start)
# print("file upon pause: ", file_upon_pause)
# print("file upon stop: ", file_upon_stop)
if self.loop == "On":
loop = "1"
else:
loop = "0"
self.app.canvas.core.mobilityconfig_management.set_custom_configuration(
node_id=self.node.id,
file=file,
refresh_ms=refresh_time,
loop=loop,
autostart=auto_start_seconds,
node_mapping=node_mapping,
script_start=file_upon_start,
script_pause=file_upon_pause,
script_stop=file_upon_stop,
)
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.mobility_configs[self.node.id] = self.config
self.destroy()
def ns2script_options(self):
"""
create the options for ns2script configuration
:return: nothing
"""
f = ttk.Frame(self.top)
b = ttk.Button(f, text="Apply", command=self.ns2script_apply)
b.grid()
b = ttk.Button(f, text="Cancel", command=self.destroy)
b.grid(row=0, column=1)
f.grid()

View file

@ -5,7 +5,6 @@ wlan configuration
from tkinter import ttk
from coretk.dialogs.dialog import Dialog
from coretk.dialogs.mobilityconfig import MobilityConfigDialog
from coretk.widgets import ConfigFrame
PAD = 5
@ -46,10 +45,6 @@ class WlanConfigDialog(Dialog):
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
def click_mobility(self):
dialog = MobilityConfigDialog(self, self.app, self.canvas_node)
dialog.show()
def click_apply(self):
"""
retrieve user's wlan configuration and store the new configuration values

View file

@ -1,75 +0,0 @@
"""
mobility configurations for all the nodes
"""
import logging
from collections import OrderedDict
from core.api.grpc import core_pb2
class MobilityNodeConfig:
def __init__(self):
"""
create an instance of MobilityConfig object
"""
# dict that maps node id to mobility configuration
self.configurations = {}
def set_default_configuration(self, node_type, node_id):
"""
set default mobility configuration for a node
:param core_pb2.NodeType node_type: protobuf node type
:param int node_id: node id
:return: nothing
"""
if node_type == core_pb2.NodeType.WIRELESS_LAN:
config = OrderedDict()
config["autostart"] = ""
config["file"] = ""
config["loop"] = "1"
config["map"] = ""
config["refresh_ms"] = "50"
config["script_pause"] = ""
config["script_start"] = ""
config["script_stop"] = ""
self.configurations[node_id] = config
def set_custom_configuration(
self,
node_id,
file,
refresh_ms,
loop,
autostart,
node_mapping,
script_start,
script_pause,
script_stop,
):
"""
set custom mobility configuration for a node
:param int node_id: node id
:param str file: path to mobility script file
:param str refresh_ms: refresh time
:param str loop: loop option
:param str autostart: auto-start seconds value
:param str node_mapping: node mapping
:param str script_start: path to script to run upon start
:param str script_pause: path to script to run upon pause
:param str script_stop: path to script to run upon stop
:return: nothing
"""
if node_id in self.configurations:
self.configurations[node_id]["autostart"] = autostart
self.configurations[node_id]["file"] = file
self.configurations[node_id]["loop"] = loop
self.configurations[node_id]["map"] = node_mapping
self.configurations[node_id]["refresh_ms"] = refresh_ms
self.configurations[node_id]["script_pause"] = script_pause
self.configurations[node_id]["script_start"] = script_start
self.configurations[node_id]["script_stop"] = script_stop
else:
logging.error("mobilitynodeconfig.py invalid node_id")

View file

@ -30,6 +30,8 @@ def add_node_data(node_proto):
options.opaque = node_proto.opaque
options.image = node_proto.image
options.services = node_proto.services
if node_proto.emane:
options.emane = node_proto.emane
if node_proto.server:
options.server = node_proto.server

View file

@ -713,10 +713,6 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
session = self.get_session(request.session_id, context)
_type, _id, options = grpcutils.add_node_data(request.node)
node = session.add_node(_type=_type, _id=_id, options=options)
# configure emane if provided
emane_model = request.node.emane
if emane_model:
session.emane.set_model_config(id, emane_model)
return core_pb2.AddNodeResponse(node_id=node.id)
def GetNode(self, request, context):

View file

@ -89,6 +89,7 @@ class NodeOptions:
self.emulation_id = None
self.server = None
self.image = image
self.emane = None
def set_position(self, x, y):
"""

View file

@ -30,7 +30,7 @@ from core.emulator.sessionconfig import SessionConfig
from core.errors import CoreError
from core.location.corelocation import CoreLocation
from core.location.event import EventLoop
from core.location.mobility import MobilityManager
from core.location.mobility import BasicRangeModel, MobilityManager
from core.nodes.base import CoreNetworkBase, CoreNode, CoreNodeBase
from core.nodes.docker import DockerNode
from core.nodes.ipaddress import MacAddress
@ -703,6 +703,13 @@ class Session:
logging.debug("set node type: %s", node.type)
self.services.add_services(node, node.type, options.services)
# ensure default emane configuration
if _type == NodeTypes.EMANE:
self.emane.set_model_config(_id, node.emane)
# set default wlan config if needed
if _type == NodeTypes.WIRELESS_LAN:
self.mobility.set_model_config(_id, BasicRangeModel.name)
# boot nodes after runtime, CoreNodes, Physical, and RJ45 are all nodes
is_boot_node = isinstance(node, CoreNodeBase) and not isinstance(node, Rj45Node)
if self.state == EventTypes.RUNTIME_STATE.value and is_boot_node: