From d343bd06552aba1b56178dff058586e5fa27da76 Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Fri, 13 Dec 2019 08:48:40 -0800 Subject: [PATCH 1/9] updated gui to display custom icons if set, updated grpc to send custon icon and image data when present --- coretk/coretk/dialogs/nodeconfig.py | 6 ++++++ coretk/coretk/graph/graph.py | 9 +++++++++ daemon/core/api/grpc/server.py | 5 +++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/coretk/coretk/dialogs/nodeconfig.py b/coretk/coretk/dialogs/nodeconfig.py index 8f4ad8a9..c71a1b34 100644 --- a/coretk/coretk/dialogs/nodeconfig.py +++ b/coretk/coretk/dialogs/nodeconfig.py @@ -46,6 +46,7 @@ class NodeConfigDialog(Dialog): self.canvas_node = canvas_node self.node = canvas_node.core_node self.image = canvas_node.image + self.image_file = None self.image_button = None self.name = tk.StringVar(value=self.node.name) self.type = tk.StringVar(value=self.node.model) @@ -201,6 +202,7 @@ class NodeConfigDialog(Dialog): if file_path: self.image = Images.create(file_path, nodeutils.ICON_SIZE) self.image_button.config(image=self.image) + self.image_file = file_path def config_apply(self): # update core node @@ -211,6 +213,10 @@ class NodeConfigDialog(Dialog): if NodeUtils.is_container_node(self.node.type) and server != "localhost": self.node.server = server + # set custom icon + if self.image_file: + self.node.icon = self.image_file + # update canvas node self.canvas_node.image = self.image diff --git a/coretk/coretk/graph/graph.py b/coretk/coretk/graph/graph.py index e439b842..baa18170 100644 --- a/coretk/coretk/graph/graph.py +++ b/coretk/coretk/graph/graph.py @@ -4,6 +4,7 @@ import tkinter as tk from PIL import Image, ImageTk from core.api.grpc import core_pb2 +from coretk import nodeutils from coretk.dialogs.shapemod import ShapeDialog from coretk.graph import tags from coretk.graph.edges import CanvasEdge, CanvasWirelessEdge @@ -12,6 +13,7 @@ from coretk.graph.linkinfo import LinkInfo, Throughput from coretk.graph.node import CanvasNode from coretk.graph.shape import Shape from coretk.graph.shapeutils import ShapeType, is_draw_shape +from coretk.images import Images from coretk.nodeutils import NodeUtils ZOOM_IN = 1.1 @@ -186,12 +188,19 @@ class CanvasGraph(tk.Canvas): """ # draw existing nodes for core_node in session.nodes: + logging.info("drawing core node: %s", core_node) # peer to peer node is not drawn on the GUI if NodeUtils.is_ignore_node(core_node.type): continue # draw nodes on the canvas image = NodeUtils.node_icon(core_node.type, core_node.model) + if core_node.icon: + try: + image = Images.create(core_node.icon, nodeutils.ICON_SIZE) + except OSError: + logging.error("invalid icon: %s", core_node.icon) + x = core_node.position.x y = core_node.position.y node = CanvasNode(self.master, x, y, core_node, image) diff --git a/daemon/core/api/grpc/server.py b/daemon/core/api/grpc/server.py index dac09427..fd1a73c3 100644 --- a/daemon/core/api/grpc/server.py +++ b/daemon/core/api/grpc/server.py @@ -393,15 +393,14 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): position = core_pb2.Position( x=node.position.x, y=node.position.y, z=node.position.z ) - services = getattr(node, "services", []) if services is None: services = [] services = [x.name for x in services] - emane_model = None if isinstance(node, EmaneNet): emane_model = node.model.name + image = getattr(node, "image", None) node_proto = core_pb2.Node( id=node.id, @@ -411,6 +410,8 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): type=node_type.value, position=position, services=services, + icon=node.icon, + image=image, ) if isinstance(node, (DockerNode, LxcNode)): node_proto.image = node.image From 9c302e8bc672c62c752da787bb2f0ddf42d812a8 Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Fri, 13 Dec 2019 09:28:51 -0800 Subject: [PATCH 2/9] added some basic boundary checking for moving nodes and shapes --- coretk/coretk/graph/graph.py | 12 ++++++++++++ coretk/coretk/graph/node.py | 11 ++++++++++- coretk/coretk/graph/shape.py | 6 ++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/coretk/coretk/graph/graph.py b/coretk/coretk/graph/graph.py index baa18170..42dbc934 100644 --- a/coretk/coretk/graph/graph.py +++ b/coretk/coretk/graph/graph.py @@ -138,6 +138,11 @@ class CanvasGraph(tk.Canvas): valid_y = y1 <= y <= y2 return valid_x and valid_y + def valid_position(self, x1, y1, x2, y2): + valid_topleft = self.inside_canvas(x1, y1) + valid_bottomright = self.inside_canvas(x2, y2) + return valid_topleft and valid_bottomright + def draw_grid(self): """ Create grid. @@ -539,6 +544,13 @@ class CanvasGraph(tk.Canvas): """ x, y = self.canvas_xy(event) if not self.inside_canvas(x, y): + if self.select_box: + self.select_box.delete() + self.select_box = None + if is_draw_shape(self.annotation_type) and self.shape_drawing: + shape = self.shapes.pop(self.selected) + shape.delete() + self.shape_drawing = False return x_offset = x - self.cursor[0] diff --git a/coretk/coretk/graph/node.py b/coretk/coretk/graph/node.py index a0f406f7..11c7eaf5 100644 --- a/coretk/coretk/graph/node.py +++ b/coretk/coretk/graph/node.py @@ -103,10 +103,19 @@ class CanvasNode: self.motion(x_offset, y_offset, update=False) def motion(self, x_offset, y_offset, update=True): + original_position = self.canvas.coords(self.id) self.canvas.move(self.id, x_offset, y_offset) + x, y = self.canvas.coords(self.id) + + # check new position + bbox = self.canvas.bbox(self.id) + if not self.canvas.valid_position(*bbox): + self.canvas.coords(self.id, original_position) + return + + # move test and selection box self.canvas.move(self.text_id, x_offset, y_offset) self.canvas.move_selection(self.id, x_offset, y_offset) - x, y = self.canvas.coords(self.id) # move antennae for antenna_id in self.antennae: diff --git a/coretk/coretk/graph/shape.py b/coretk/coretk/graph/shape.py index 99a18a9f..e7277b49 100644 --- a/coretk/coretk/graph/shape.py +++ b/coretk/coretk/graph/shape.py @@ -136,7 +136,13 @@ class Shape: self.canvas.delete(self.id) def motion(self, x_offset, y_offset): + original_position = self.canvas.coords(self.id) self.canvas.move(self.id, x_offset, y_offset) + coords = self.canvas.coords(self.id) + if not self.canvas.valid_position(*coords): + self.canvas.coords(self.id, original_position) + return + self.canvas.move_selection(self.id, x_offset, y_offset) if self.text_id is not None: self.canvas.move(self.text_id, x_offset, y_offset) From 819954a695d1a6e0b2cb721c68ca83b1761543dc Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Fri, 13 Dec 2019 10:47:23 -0800 Subject: [PATCH 3/9] updated grpc node positions to use floats, avoids needing to deal with int conversions --- coretk/coretk/coreclient.py | 3 +-- coretk/coretk/graph/graph.py | 5 +---- coretk/coretk/graph/node.py | 9 ++------- daemon/core/api/grpc/server.py | 8 +------- daemon/core/xml/corexml.py | 14 ++++---------- daemon/proto/core/api/grpc/core.proto | 6 +++--- 6 files changed, 12 insertions(+), 33 deletions(-) diff --git a/coretk/coretk/coreclient.py b/coretk/coretk/coreclient.py index ec6ca772..a5f407b7 100644 --- a/coretk/coretk/coreclient.py +++ b/coretk/coretk/coreclient.py @@ -183,8 +183,7 @@ class CoreClient: ) def handle_exception_event(self, event): - print(event) - print(event.node_id) + logging.info("exception event: %s", event) self.app.statusbar.core_alarms.append(event) def join_session(self, session_id, query_location=True): diff --git a/coretk/coretk/graph/graph.py b/coretk/coretk/graph/graph.py index 42dbc934..a2d82dc4 100644 --- a/coretk/coretk/graph/graph.py +++ b/coretk/coretk/graph/graph.py @@ -616,10 +616,7 @@ class CanvasGraph(tk.Canvas): if self.selected is None or self.selected in self.shapes: actual_x, actual_y = self.get_actual_coords(x, y) core_node = self.core.create_node( - int(actual_x), - int(actual_y), - self.node_draw.node_type, - self.node_draw.model, + actual_x, actual_y, self.node_draw.node_type, self.node_draw.model ) node = CanvasNode(self.master, x, y, core_node, self.node_draw.image) self.core.canvas_nodes[core_node.id] = node diff --git a/coretk/coretk/graph/node.py b/coretk/coretk/graph/node.py index 11c7eaf5..0d0f8706 100644 --- a/coretk/coretk/graph/node.py +++ b/coretk/coretk/graph/node.py @@ -140,8 +140,8 @@ class CanvasNode: # set actual coords for node and update core is running real_x, real_y = self.canvas.get_actual_coords(x, y) - self.core_node.position.x = int(real_x) - self.core_node.position.y = int(real_y) + self.core_node.position.x = real_x + self.core_node.position.y = real_y if self.app.core.is_runtime() and update: self.app.core.edit_node(self.core_node) @@ -164,11 +164,6 @@ class CanvasNode: else: self.show_config() - def update_coords(self): - x, y = self.canvas.coords(self.id) - self.core_node.position.x = int(x) - self.core_node.position.y = int(y) - def create_context(self): is_wlan = self.core_node.type == NodeType.WIRELESS_LAN is_emane = self.core_node.type == NodeType.EMANE diff --git a/daemon/core/api/grpc/server.py b/daemon/core/api/grpc/server.py index fd1a73c3..4ee32751 100644 --- a/daemon/core/api/grpc/server.py +++ b/daemon/core/api/grpc/server.py @@ -489,13 +489,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): :return: node event that contains node id, name, model, position, and services :rtype: core.api.grpc.core_pb2.NodeEvent """ - x = None - if event.x_position is not None: - x = int(event.x_position) - y = None - if event.y_position is not None: - y = int(event.y_position) - position = core_pb2.Position(x=x, y=y) + position = core_pb2.Position(x=event.x_position, y=event.y_position) services = event.services or "" services = services.split("|") node_proto = core_pb2.Node( diff --git a/daemon/core/xml/corexml.py b/daemon/core/xml/corexml.py index 9ba63395..285b7a3b 100644 --- a/daemon/core/xml/corexml.py +++ b/daemon/core/xml/corexml.py @@ -117,14 +117,8 @@ class NodeElement: def add_position(self): x = self.node.position.x - if x is not None: - x = int(x) y = self.node.position.y - if y is not None: - y = int(y) z = self.node.position.z - if z is not None: - z = int(z) lat, lon, alt = None, None, None if x is not None and y is not None: lat, lon, alt = self.session.location.getgeo(x, y, z) @@ -751,8 +745,8 @@ class CoreXmlReader: position_element = device_element.find("position") if position_element is not None: - x = get_int(position_element, "x") - y = get_int(position_element, "y") + x = get_float(position_element, "x") + y = get_float(position_element, "y") if all([x, y]): options.set_position(x, y) @@ -773,8 +767,8 @@ class CoreXmlReader: position_element = network_element.find("position") if position_element is not None: - x = get_int(position_element, "x") - y = get_int(position_element, "y") + x = get_float(position_element, "x") + y = get_float(position_element, "y") if all([x, y]): options.set_position(x, y) diff --git a/daemon/proto/core/api/grpc/core.proto b/daemon/proto/core/api/grpc/core.proto index 57bbf3f4..253102bf 100644 --- a/daemon/proto/core/api/grpc/core.proto +++ b/daemon/proto/core/api/grpc/core.proto @@ -949,9 +949,9 @@ message SessionLocation { } message Position { - int32 x = 1; - int32 y = 2; - int32 z = 3; + float x = 1; + float y = 2; + float z = 3; float lat = 4; float lon = 5; float alt = 6; From 358985d1292f08a016eedbcf439f4402d8a3c1d3 Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Fri, 13 Dec 2019 10:54:42 -0800 Subject: [PATCH 4/9] update to avoid not reusing session ids --- daemon/core/emulator/coreemu.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/daemon/core/emulator/coreemu.py b/daemon/core/emulator/coreemu.py index cdba4e44..158dc296 100644 --- a/daemon/core/emulator/coreemu.py +++ b/daemon/core/emulator/coreemu.py @@ -5,7 +5,6 @@ import signal import sys import core.services -from core.emulator.emudata import IdGen from core.emulator.session import Session from core.services.coreservices import ServiceManager @@ -49,7 +48,6 @@ class CoreEmu: self.config = config # session management - self.session_id_gen = IdGen() self.sessions = {} # load services @@ -79,7 +77,6 @@ class CoreEmu: :return: nothing """ logging.info("shutting down all sessions") - self.session_id_gen.id = 0 sessions = self.sessions.copy() self.sessions.clear() for _id in sessions: @@ -96,11 +93,9 @@ class CoreEmu: :rtype: EmuSession """ if not _id: - while True: - _id = self.session_id_gen.next() - if _id not in self.sessions: - break - + _id = 1 + while _id in self.sessions: + _id += 1 session = _cls(_id, config=self.config) logging.info("created session: %s", _id) self.sessions[_id] = session From b993fadedb91f0439decfd889cd881803d52d909 Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Fri, 13 Dec 2019 11:24:35 -0800 Subject: [PATCH 5/9] removed grpc check for getting a node service file, it will return the default value when not currently set --- daemon/core/api/grpc/server.py | 7 ------- daemon/core/services/coreservices.py | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/daemon/core/api/grpc/server.py b/daemon/core/api/grpc/server.py index 4ee32751..27b069f0 100644 --- a/daemon/core/api/grpc/server.py +++ b/daemon/core/api/grpc/server.py @@ -1158,13 +1158,6 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): logging.debug("get node service file: %s", request) session = self.get_session(request.session_id, context) node = self.get_node(session, request.node_id, context) - service = None - for current_service in node.services: - if current_service.name == request.service: - service = current_service - break - if not service: - context.abort(grpc.StatusCode.NOT_FOUND, "service not found") file_data = session.services.get_service_file( node, request.service, request.file ) diff --git a/daemon/core/services/coreservices.py b/daemon/core/services/coreservices.py index 361061be..b51eb715 100644 --- a/daemon/core/services/coreservices.py +++ b/daemon/core/services/coreservices.py @@ -396,7 +396,7 @@ class CoreServices: """ Add services to a node. - :param core.coreobj.PyCoreNode node: node to add services to + :param core.nodes.base.CoreNode node: node to add services to :param str node_type: node type to add services to :param list[str] services: names of services to add to node :return: nothing From 9b16f272b86f73c39ab20e60c6ea527caeae79cc Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Fri, 13 Dec 2019 11:48:36 -0800 Subject: [PATCH 6/9] added get wlan configs, made use of it in coretk, updated node context to allow wlan config during runtime --- coretk/coretk/coreclient.py | 12 +++++++----- coretk/coretk/graph/node.py | 2 ++ daemon/core/api/grpc/client.py | 12 ++++++++++++ daemon/core/api/grpc/server.py | 25 +++++++++++++++++++++++++ daemon/proto/core/api/grpc/core.proto | 10 ++++++++++ 5 files changed, 56 insertions(+), 5 deletions(-) diff --git a/coretk/coretk/coreclient.py b/coretk/coretk/coreclient.py index a5f407b7..f9ac0384 100644 --- a/coretk/coretk/coreclient.py +++ b/coretk/coretk/coreclient.py @@ -239,15 +239,17 @@ class CoreClient: node_id, config.model, config.config, interface ) + # get wlan configurations + response = self.client.get_wlan_configs(self.session_id) + for _id in response.configs: + mapped_config = response.configs[_id] + self.wlan_configs[_id] = mapped_config.config + # save and retrieve data, needed for session nodes for node in session.nodes: # get node service config and file config - # get wlan configs for wlan nodes - if node.type == core_pb2.NodeType.WIRELESS_LAN: - response = self.client.get_wlan_config(self.session_id, node.id) - self.wlan_configs[node.id] = response.config # retrieve service configurations data for default nodes - elif node.type == core_pb2.NodeType.DEFAULT: + if node.type == core_pb2.NodeType.DEFAULT: for service in node.services: response = self.client.get_node_service( self.session_id, node.id, service diff --git a/coretk/coretk/graph/node.py b/coretk/coretk/graph/node.py index 0d0f8706..93b6c390 100644 --- a/coretk/coretk/graph/node.py +++ b/coretk/coretk/graph/node.py @@ -173,6 +173,8 @@ class CanvasNode: context.add_command(label="Configure", command=self.show_config) if NodeUtils.is_container_node(self.core_node.type): context.add_command(label="Services", state=tk.DISABLED) + if is_wlan: + context.add_command(label="WLAN Config", command=self.show_wlan_config) if is_wlan and self.core_node.id in self.app.core.mobility_players: context.add_command( label="Mobility Player", command=self.show_mobility_player diff --git a/daemon/core/api/grpc/client.py b/daemon/core/api/grpc/client.py index 05380b79..7887d5e8 100644 --- a/daemon/core/api/grpc/client.py +++ b/daemon/core/api/grpc/client.py @@ -827,6 +827,18 @@ class CoreGrpcClient: ) return self.stub.ServiceAction(request) + def get_wlan_configs(self, session_id): + """ + Get all wlan configurations. + + :param int session_id: session id + :return: response with a dict of node ids to wlan configurations + :rtype: core_pb2.GetWlanConfigsResponse + :raises grpc.RpcError: when session doesn't exist + """ + request = core_pb2.GetWlanConfigsRequest(session_id=session_id) + return self.stub.GetWlanConfigs(request) + def get_wlan_config(self, session_id, node_id): """ Get wlan configuration for a node. diff --git a/daemon/core/api/grpc/server.py b/daemon/core/api/grpc/server.py index 27b069f0..9b8c51c7 100644 --- a/daemon/core/api/grpc/server.py +++ b/daemon/core/api/grpc/server.py @@ -1236,6 +1236,31 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): return core_pb2.ServiceActionResponse(result=result) + def GetWlanConfigs(self, request, context): + """ + Retrieve all wireless-lan configurations. + + :param core.api.grpc.core_pb2.GetWlanConfigsRequest request: request + :param context: core.api.grpc.core_pb2.GetWlanConfigResponse + :return: all wlan configurations + :rtype: core.api.grpc.core_pb2.GetWlanConfigsResponse + """ + logging.debug("get wlan configs: %s", request) + session = self.get_session(request.session_id, context) + response = core_pb2.GetWlanConfigsResponse() + for node_id in session.mobility.node_configurations: + model_config = session.mobility.node_configurations[node_id] + if node_id == -1: + continue + for model_name in model_config: + if model_name != BasicRangeModel.name: + continue + current_config = session.mobility.get_model_config(node_id, model_name) + config = get_config_options(current_config, BasicRangeModel) + mapped_config = core_pb2.MappedConfig(config=config) + response.configs[node_id].CopyFrom(mapped_config) + return response + def GetWlanConfig(self, request, context): """ Retrieve wireless-lan configuration of a node diff --git a/daemon/proto/core/api/grpc/core.proto b/daemon/proto/core/api/grpc/core.proto index 253102bf..609316f8 100644 --- a/daemon/proto/core/api/grpc/core.proto +++ b/daemon/proto/core/api/grpc/core.proto @@ -101,6 +101,8 @@ service CoreApi { } // wlan rpc + rpc GetWlanConfigs (GetWlanConfigsRequest) returns (GetWlanConfigsResponse) { + } rpc GetWlanConfig (GetWlanConfigRequest) returns (GetWlanConfigResponse) { } rpc SetWlanConfig (SetWlanConfigRequest) returns (SetWlanConfigResponse) { @@ -585,6 +587,14 @@ message ServiceActionResponse { bool result = 1; } +message GetWlanConfigsRequest { + int32 session_id = 1; +} + +message GetWlanConfigsResponse { + map configs = 1; +} + message GetWlanConfigRequest { int32 session_id = 1; int32 node_id = 2; From 9ada94107e1db5cbe273dec43ba3d3a7c1ff0d7c Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Fri, 13 Dec 2019 14:03:41 -0800 Subject: [PATCH 7/9] changes to grpc get emane model configs to return the interface value and actual node id, instead of coded value that would need to be parsed --- coretk/coretk/coreclient.py | 10 ++++------ daemon/core/api/grpc/grpcutils.py | 16 ++++++++++++++++ daemon/core/api/grpc/server.py | 11 ++++++----- daemon/proto/core/api/grpc/core.proto | 1 + 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/coretk/coretk/coreclient.py b/coretk/coretk/coreclient.py index f9ac0384..86451338 100644 --- a/coretk/coretk/coreclient.py +++ b/coretk/coretk/coreclient.py @@ -228,13 +228,11 @@ class CoreClient: # get emane model config response = self.client.get_emane_model_configs(self.session_id) - for _id in response.configs: - config = response.configs[_id] + for node_id in response.configs: + config = response.configs[node_id] interface = None - node_id = _id - if _id >= 1000: - interface = _id % 1000 - node_id = int(_id / 1000) + if config.interface != -1: + interface = config.interface self.set_emane_model_config( node_id, config.model, config.config, interface ) diff --git a/daemon/core/api/grpc/grpcutils.py b/daemon/core/api/grpc/grpcutils.py index cf1250c8..7df86a18 100644 --- a/daemon/core/api/grpc/grpcutils.py +++ b/daemon/core/api/grpc/grpcutils.py @@ -221,6 +221,22 @@ def get_emane_model_id(node_id, interface_id): return node_id +def parse_emane_model_id(_id): + """ + Parses EMANE model id to get true node id and interface id. + + :param _id: id to parse + :return: node id and interface id + :rtype: tuple + """ + interface = -1 + node_id = _id + if _id >= 1000: + interface = _id % 1000 + node_id = int(_id / 1000) + return node_id, interface + + def convert_link(session, link_data): """ Convert link_data into core protobuf Link diff --git a/daemon/core/api/grpc/server.py b/daemon/core/api/grpc/server.py index 9b8c51c7..0b566333 100644 --- a/daemon/core/api/grpc/server.py +++ b/daemon/core/api/grpc/server.py @@ -1395,17 +1395,18 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): logging.debug("get emane model configs: %s", request) session = self.get_session(request.session_id, context) response = core_pb2.GetEmaneModelConfigsResponse() - for node_id in session.emane.node_configurations: - model_config = session.emane.node_configurations[node_id] - if node_id == -1: + for _id in session.emane.node_configurations: + if _id == -1: continue + model_config = session.emane.node_configurations[_id] for model_name in model_config: model = session.emane.models[model_name] - current_config = session.emane.get_model_config(node_id, model_name) + current_config = session.emane.get_model_config(_id, model_name) config = get_config_options(current_config, model) + node_id, interface = grpcutils.parse_emane_model_id(_id) model_config = core_pb2.GetEmaneModelConfigsResponse.ModelConfig( - model=model_name, config=config + model=model_name, config=config, interface=interface ) response.configs[node_id].CopyFrom(model_config) return response diff --git a/daemon/proto/core/api/grpc/core.proto b/daemon/proto/core/api/grpc/core.proto index 609316f8..fb7aaadc 100644 --- a/daemon/proto/core/api/grpc/core.proto +++ b/daemon/proto/core/api/grpc/core.proto @@ -666,6 +666,7 @@ message GetEmaneModelConfigsResponse { message ModelConfig { string model = 1; map config = 2; + int32 interface = 3; } map configs = 1; } From 9d988a4b138f740c36f3671496f1c2325ea1af75 Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Fri, 13 Dec 2019 14:18:13 -0800 Subject: [PATCH 8/9] fixed issue in grpc get emane model configs that would allow key collision --- coretk/coretk/coreclient.py | 5 ++--- daemon/core/api/grpc/server.py | 16 ++++++++++------ daemon/proto/core/api/grpc/core.proto | 7 ++++--- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/coretk/coretk/coreclient.py b/coretk/coretk/coreclient.py index 86451338..bff47501 100644 --- a/coretk/coretk/coreclient.py +++ b/coretk/coretk/coreclient.py @@ -228,13 +228,12 @@ class CoreClient: # get emane model config response = self.client.get_emane_model_configs(self.session_id) - for node_id in response.configs: - config = response.configs[node_id] + for config in response.configs: interface = None if config.interface != -1: interface = config.interface self.set_emane_model_config( - node_id, config.model, config.config, interface + config.node_id, config.model, config.config, interface ) # get wlan configurations diff --git a/daemon/core/api/grpc/server.py b/daemon/core/api/grpc/server.py index 0b566333..e552e1a4 100644 --- a/daemon/core/api/grpc/server.py +++ b/daemon/core/api/grpc/server.py @@ -1394,22 +1394,26 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): """ logging.debug("get emane model configs: %s", request) session = self.get_session(request.session_id, context) - response = core_pb2.GetEmaneModelConfigsResponse() + + configs = [] for _id in session.emane.node_configurations: if _id == -1: continue - model_config = session.emane.node_configurations[_id] - for model_name in model_config: + model_configs = session.emane.node_configurations[_id] + for model_name in model_configs: model = session.emane.models[model_name] current_config = session.emane.get_model_config(_id, model_name) config = get_config_options(current_config, model) node_id, interface = grpcutils.parse_emane_model_id(_id) model_config = core_pb2.GetEmaneModelConfigsResponse.ModelConfig( - model=model_name, config=config, interface=interface + node_id=node_id, + model=model_name, + interface=interface, + config=config, ) - response.configs[node_id].CopyFrom(model_config) - return response + configs.append(model_config) + return core_pb2.GetEmaneModelConfigsResponse(configs=configs) def SaveXml(self, request, context): """ diff --git a/daemon/proto/core/api/grpc/core.proto b/daemon/proto/core/api/grpc/core.proto index fb7aaadc..5f6a964b 100644 --- a/daemon/proto/core/api/grpc/core.proto +++ b/daemon/proto/core/api/grpc/core.proto @@ -664,11 +664,12 @@ message GetEmaneModelConfigsRequest { message GetEmaneModelConfigsResponse { message ModelConfig { - string model = 1; - map config = 2; + int32 node_id = 1; + string model = 2; int32 interface = 3; + map config = 4; } - map configs = 1; + repeated ModelConfig configs = 1; } message SaveXmlRequest { From 47e087b3651d14a3437f4e468a8bca138428d9ad Mon Sep 17 00:00:00 2001 From: Blake Harnden <32446120+bharnden@users.noreply.github.com> Date: Fri, 13 Dec 2019 15:28:22 -0800 Subject: [PATCH 9/9] fixed unit tests for grpc get emane model configs --- daemon/tests/test_grpc.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/daemon/tests/test_grpc.py b/daemon/tests/test_grpc.py index 4446a74e..d4df63d7 100644 --- a/daemon/tests/test_grpc.py +++ b/daemon/tests/test_grpc.py @@ -708,10 +708,11 @@ class TestGrpc: # then assert len(response.configs) == 1 - assert emane_network.id in response.configs - model_config = response.configs[emane_network.id] + model_config = response.configs[0] + assert emane_network.id == model_config.node_id assert model_config.model == EmaneIeee80211abgModel.name assert len(model_config.config) > 0 + assert model_config.interface == -1 def test_set_emane_model_config(self, grpc_server): # given