From eced9863ad488928024edecbc839728577a4600d Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Thu, 21 Nov 2019 09:40:57 -0800 Subject: [PATCH 1/2] removed mobility config class to try and help simplify saving configs --- coretk/coretk/coreclient.py | 32 +-- coretk/coretk/dialogs/mobilityconfig.py | 250 +++--------------------- coretk/coretk/dialogs/wlanconfig.py | 5 - coretk/coretk/mobilitynodeconfig.py | 75 ------- 4 files changed, 48 insertions(+), 314 deletions(-) delete mode 100644 coretk/coretk/mobilitynodeconfig.py diff --git a/coretk/coretk/coreclient.py b/coretk/coretk/coreclient.py index fed8040a..93ebba4c 100644 --- a/coretk/coretk/coreclient.py +++ b/coretk/coretk/coreclient.py @@ -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): @@ -678,3 +672,11 @@ class CoreClient: 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 + self.mobility_configs[node_id] = config + return config diff --git a/coretk/coretk/dialogs/mobilityconfig.py b/coretk/coretk/dialogs/mobilityconfig.py index 2c20229a..21782ee6 100644 --- a/coretk/coretk/dialogs/mobilityconfig.py +++ b/coretk/coretk/dialogs/mobilityconfig.py @@ -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() diff --git a/coretk/coretk/dialogs/wlanconfig.py b/coretk/coretk/dialogs/wlanconfig.py index 3973efb5..3c118834 100644 --- a/coretk/coretk/dialogs/wlanconfig.py +++ b/coretk/coretk/dialogs/wlanconfig.py @@ -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 diff --git a/coretk/coretk/mobilitynodeconfig.py b/coretk/coretk/mobilitynodeconfig.py deleted file mode 100644 index 4a94f573..00000000 --- a/coretk/coretk/mobilitynodeconfig.py +++ /dev/null @@ -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") From 9445b63bd2eb7ea44c2b45d39a49a9f2c576aa54 Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Thu, 21 Nov 2019 12:29:33 -0800 Subject: [PATCH 2/2] removed saving default configurations for wlan and mobility by default, updated session.add_node to set default configurations for wlan and emane --- coretk/coretk/coreclient.py | 2 -- daemon/core/api/grpc/grpcutils.py | 2 ++ daemon/core/api/grpc/server.py | 4 ---- daemon/core/emulator/emudata.py | 1 + daemon/core/emulator/session.py | 9 ++++++++- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/coretk/coretk/coreclient.py b/coretk/coretk/coreclient.py index 93ebba4c..beeb1c0a 100644 --- a/coretk/coretk/coreclient.py +++ b/coretk/coretk/coreclient.py @@ -670,7 +670,6 @@ 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): @@ -678,5 +677,4 @@ class CoreClient: if not config: response = self.client.get_mobility_config(self.session_id, node_id) config = response.config - self.mobility_configs[node_id] = config return config diff --git a/daemon/core/api/grpc/grpcutils.py b/daemon/core/api/grpc/grpcutils.py index c6b625fb..cf1250c8 100644 --- a/daemon/core/api/grpc/grpcutils.py +++ b/daemon/core/api/grpc/grpcutils.py @@ -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 diff --git a/daemon/core/api/grpc/server.py b/daemon/core/api/grpc/server.py index 8c987371..79053eee 100644 --- a/daemon/core/api/grpc/server.py +++ b/daemon/core/api/grpc/server.py @@ -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): diff --git a/daemon/core/emulator/emudata.py b/daemon/core/emulator/emudata.py index 5e59eaae..2a8f9bf6 100644 --- a/daemon/core/emulator/emudata.py +++ b/daemon/core/emulator/emudata.py @@ -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): """ diff --git a/daemon/core/emulator/session.py b/daemon/core/emulator/session.py index cba99e8e..4852d026 100644 --- a/daemon/core/emulator/session.py +++ b/daemon/core/emulator/session.py @@ -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: