update node creation and storage to leverage protobufs directly

This commit is contained in:
bharnden 2019-11-15 10:22:30 -08:00
parent fa76bbf01b
commit 6d38058887
10 changed files with 216 additions and 516 deletions

View file

@ -36,8 +36,6 @@ class CanvasAction:
self.node_to_show_config = None
def display_wlan_configuration(self, canvas_node):
# print(self.canvas.grpc_manager.wlanconfig_management.configurations)
wlan_config = self.master.core.wlanconfig_management.configurations[
canvas_node.core_id
]

View file

@ -5,7 +5,6 @@ import logging
import os
from core.api.grpc import client, core_pb2
from coretk.coretocanvas import CoreToCanvasMapping
from coretk.dialogs.sessions import SessionsDialog
from coretk.emaneodelnodeconfig import EmaneModelNodeConfig
from coretk.images import NODE_WIDTH, Images
@ -29,28 +28,6 @@ OBSERVERS = {
}
class Node:
def __init__(self, session_id, node_id, node_type, model, x, y, name):
"""
Create an instance of a node
:param int session_id: session id
:param int node_id: node id
:param core_pb2.NodeType node_type: node type
:param int x: x coordinate
:param int y: coordinate
:param str name: node name
"""
self.session_id = session_id
self.node_id = node_id
self.type = node_type
self.x = x
self.y = y
self.model = model
self.name = name
self.interfaces = []
class Edge:
def __init__(self, session_id, node_id_1, node_type_1, node_id_2, node_type_2):
"""
@ -112,15 +89,15 @@ class CoreClient:
self.read_config()
# data for managing the current session
self.canvas_nodes = {}
self.interface_to_edge = {}
self.state = None
self.nodes = {}
self.edges = {}
self.hooks = {}
self.id = 1
self.reusable = []
self.preexisting = set()
self.interfaces_manager = InterfaceManager()
self.core_mapping = CoreToCanvasMapping()
self.wlanconfig_management = WlanNodeConfig()
self.mobilityconfig_management = MobilityNodeConfig()
self.emaneconfig_management = EmaneModelNodeConfig(app)
@ -179,7 +156,7 @@ class CoreClient:
# clear session data
self.reusable.clear()
self.preexisting.clear()
self.nodes.clear()
self.canvas_nodes.clear()
self.edges.clear()
self.hooks.clear()
self.wlanconfig_management.configurations.clear()
@ -203,14 +180,14 @@ class CoreClient:
for node in session.nodes:
if node.type == core_pb2.NodeType.WIRELESS_LAN:
response = self.client.get_wlan_config(self.session_id, node.id)
logging.info("wlan config(%s): %s", node.id, response)
logging.debug("wlan config(%s): %s", node.id, response)
node_config = response.config
config = {x: node_config[x].value for x in node_config}
self.wlanconfig_management.configurations[node.id] = config
# get mobility configs
response = self.client.get_mobility_configs(self.session_id)
logging.info("mobility configs: %s", response)
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}
@ -218,7 +195,7 @@ class CoreClient:
# get emane config
response = self.client.get_emane_config(self.session_id)
logging.info("emane config: %s", response)
logging.debug("emane config: %s", response)
self.emane_config = response.config
# get emane model config
@ -339,7 +316,7 @@ class CoreClient:
logging.info("delete links %s", response)
def start_session(self):
nodes = self.get_nodes_proto()
nodes = [x.core_node for x in self.canvas_nodes.values()]
links = self.get_links_proto()
wlan_configs = self.get_wlan_configs_proto()
mobility_configs = self.get_mobility_configs_proto()
@ -411,7 +388,7 @@ class CoreClient:
logging.debug("set node service %s", response)
def create_nodes_and_links(self):
node_protos = self.get_nodes_proto()
node_protos = [x.core_node for x in self.canvas_nodes.values()]
link_protos = self.get_links_proto()
self.client.set_session_state(self.session_id, core_pb2.SessionState.DEFINITION)
for node_proto in node_protos:
@ -437,17 +414,6 @@ class CoreClient:
logging.debug("Close grpc")
self.client.close()
def peek_id(self):
"""
Peek the next id to be used
:return: nothing
"""
if len(self.reusable) == 0:
return self.id
else:
return self.reusable[0]
def get_id(self):
"""
Get the next node id as well as update id status and reusable ids
@ -465,106 +431,87 @@ class CoreClient:
def is_model_node(self, name):
return name in DEFAULT_NODES or name in self.custom_nodes
def add_graph_node(self, session_id, canvas_id, x, y, name):
def create_node(self, x, y, node_type, model):
"""
Add node, with information filled in, to grpc manager
:param int session_id: session id
:param int canvas_id: node's canvas id
:param int x: x coord
:param int y: y coord
:param str name: node type
:param core_pb2.NodeType node_type: node type
:param str model: node model
:return: nothing
"""
node_type = None
node_model = None
if name in NETWORK_NODES:
if name == "switch":
node_type = core_pb2.NodeType.SWITCH
elif name == "hub":
node_type = core_pb2.NodeType.HUB
elif name == "wlan":
node_type = core_pb2.NodeType.WIRELESS_LAN
elif name == "rj45":
node_type = core_pb2.NodeType.RJ45
elif name == "emane":
node_type = core_pb2.NodeType.EMANE
elif name == "tunnel":
node_type = core_pb2.NodeType.TUNNEL
elif name == "emane":
node_type = core_pb2.NodeType.EMANE
elif self.is_model_node(name):
node_type = core_pb2.NodeType.DEFAULT
node_model = name
else:
logging.error("invalid node name: %s", name)
nid = self.get_id()
create_node = Node(session_id, nid, node_type, node_model, x, y, name)
node_id = self.get_id()
position = core_pb2.Position(x=x, y=y)
node = core_pb2.Node(
id=node_id,
type=node_type,
name=f"n{node_id}",
model=model,
position=position,
)
# set default configuration for wireless node
self.wlanconfig_management.set_default_config(node_type, nid)
self.mobilityconfig_management.set_default_configuration(node_type, nid)
self.wlanconfig_management.set_default_config(node_type, node_id)
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(nid)
self.emaneconfig_management.set_default_config(node_id)
# set default service configurations
if node_type == core_pb2.NodeType.DEFAULT:
self.serviceconfig_manager.node_default_services_configuration(
node_id=nid, node_model=node_model
node_id=node_id, node_model=model
)
self.nodes[canvas_id] = create_node
self.core_mapping.map_core_id_to_canvas_id(nid, canvas_id)
logging.debug(
"Adding node to core.. session id: %s, coords: (%s, %s), name: %s",
session_id,
"adding node to core session: %s, coords: (%s, %s), name: %s",
self.session_id,
x,
y,
name,
node.name,
)
return node
def delete_wanted_graph_nodes(self, canvas_ids, tokens):
def delete_wanted_graph_nodes(self, node_ids, edge_tokens):
"""
remove the nodes selected by the user and anything related to that node
such as link, configurations, interfaces
:param list(int) canvas_ids: list of canvas node ids
:param list[int] node_ids: list of nodes to delete
:param list edge_tokens: list of edges to delete
:return: nothing
"""
# keep reference to the core ids
core_node_ids = [self.nodes[x].node_id for x in canvas_ids]
node_interface_pairs = []
# delete the nodes
for i in canvas_ids:
for node_id in node_ids:
try:
n = self.nodes.pop(i)
self.reusable.append(n.node_id)
del self.canvas_nodes[node_id]
self.reusable.append(node_id)
except KeyError:
logging.error("coreclient.py INVALID NODE CANVAS ID")
logging.error("invalid canvas id: %s", node_id)
self.reusable.sort()
# delete the edges and interfaces
for i in tokens:
node_interface_pairs = []
for i in edge_tokens:
try:
e = self.edges.pop(i)
if e.interface_1 is not None:
node_interface_pairs.append(tuple([e.id1, e.interface_1.id]))
if e.interface_2 is not None:
node_interface_pairs.append(tuple([e.id2, e.interface_2.id]))
except KeyError:
logging.error("coreclient.py invalid edge token ")
# delete global emane config if there no longer exist any emane cloud
if core_pb2.NodeType.EMANE not in [x.type for x in self.nodes.values()]:
# TODO: should not need to worry about this
node_types = [x.core_node.type for x in self.canvas_nodes.values()]
if core_pb2.NodeType.EMANE not in node_types:
self.emane_config = None
# delete any mobility configuration, wlan configuration
for i in core_node_ids:
for i in node_ids:
if i in self.mobilityconfig_management.configurations:
self.mobilityconfig_management.configurations.pop(i)
if i in self.wlanconfig_management.configurations:
@ -574,69 +521,16 @@ class CoreClient:
for i in node_interface_pairs:
if i in self.emaneconfig_management.configurations:
self.emaneconfig_management.configurations.pop(i)
for i in core_node_ids:
for i in node_ids:
if tuple([i, None]) in self.emaneconfig_management.configurations:
self.emaneconfig_management.configurations.pop(tuple([i, None]))
def add_preexisting_node(self, canvas_node, session_id, core_node, name):
"""
Add preexisting nodes to grpc manager
:param str name: node_type
:param core_pb2.Node core_node: core node grpc message
:param coretk.graph.CanvasNode canvas_node: canvas node
:param int session_id: session id
:return: nothing
"""
# update the next available id
core_id = core_node.id
if self.id is None or core_id >= self.id:
self.id = core_id + 1
self.preexisting.add(core_id)
n = Node(
session_id,
core_id,
core_node.type,
core_node.model,
canvas_node.x_coord,
canvas_node.y_coord,
name,
)
self.nodes[canvas_node.id] = n
def update_node_location(self, canvas_id, new_x, new_y):
"""
update node
:param int canvas_id: canvas id of that node
:param int new_x: new x coord
:param int new_y: new y coord
:return: nothing
"""
self.nodes[canvas_id].x = new_x
self.nodes[canvas_id].y = new_y
def update_reusable_id(self):
"""
Update available id for reuse
:return: nothing
"""
if len(self.preexisting) > 0:
for i in range(1, self.id):
if i not in self.preexisting:
self.reusable.append(i)
self.preexisting.clear()
logging.debug("Next id: %s, Reusable: %s", self.id, self.reusable)
def create_interface(self, node_type, gui_interface):
"""
create a protobuf interface given the interface object stored by the programmer
:param core_bp2.NodeType type: node type
:param coretk.interface.Interface gui_interface: the programmer's interface object
:param core_bp2.NodeType node_type: node type
:param coretk.interface.Interface gui_interface: the programmer's interface
:rtype: core_bp2.Interface
:return: protobuf interface object
"""
@ -653,120 +547,71 @@ class CoreClient:
logging.debug("create interface: %s", interface)
return interface
def create_edge_interface(self, edge, src_canvas_id, dst_canvas_id):
"""
Create the interface for the two end of an edge, add a copy to node's interfaces
:param coretk.coreclient.Edge edge: edge to add interfaces to
:param int src_canvas_id: canvas id for the source node
:param int dst_canvas_id: canvas id for the destination node
:return: nothing
"""
src_interface = None
dst_interface = None
print("create interface")
self.interfaces_manager.new_subnet()
src_node = self.nodes[src_canvas_id]
if self.is_model_node(src_node.model):
ifid = len(src_node.interfaces)
name = "eth" + str(ifid)
src_interface = Interface(
def create_edge_interface(self, canvas_node):
interface = None
core_node = canvas_node.core_node
if self.is_model_node(core_node.model):
ifid = len(canvas_node.interfaces)
name = f"eth{ifid}"
interface = Interface(
name=name, ifid=ifid, ipv4=str(self.interfaces_manager.get_address())
)
self.nodes[src_canvas_id].interfaces.append(src_interface)
canvas_node.interfaces.append(interface)
logging.debug(
"Create source interface 1... IP: %s, name: %s",
src_interface.ipv4,
src_interface.name,
"create node(%s) interface IP: %s, name: %s",
core_node.name,
interface.ipv4,
interface.name,
)
return interface
dst_node = self.nodes[dst_canvas_id]
if self.is_model_node(dst_node.model):
ifid = len(dst_node.interfaces)
name = "eth" + str(ifid)
dst_interface = Interface(
name=name, ifid=ifid, ipv4=str(self.interfaces_manager.get_address())
)
self.nodes[dst_canvas_id].interfaces.append(dst_interface)
logging.debug(
"Create destination interface... IP: %s, name: %s",
dst_interface.ipv4,
dst_interface.name,
)
edge.interface_1 = src_interface
edge.interface_2 = dst_interface
return src_interface, dst_interface
def add_edge(self, session_id, token, canvas_id_1, canvas_id_2):
def create_edge(self, token, canvas_node_one, canvas_node_two):
"""
Add an edge to grpc manager
:param int session_id: core session id
:param tuple(int, int) token: edge's identification in the canvas
:param int canvas_id_1: canvas id of source node
:param int canvas_id_2: canvas_id of destination node
:param canvas_node_one: canvas node one
:param canvas_node_two: canvas node two
:return: nothing
"""
node_one = self.nodes[canvas_id_1]
node_two = self.nodes[canvas_id_2]
if canvas_id_1 in self.nodes and canvas_id_2 in self.nodes:
edge = Edge(
session_id,
node_one.node_id,
node_one.type,
node_two.node_id,
node_two.type,
)
self.edges[token] = edge
src_interface, dst_interface = self.create_edge_interface(
edge, canvas_id_1, canvas_id_2
)
node_one_id = node_one.node_id
node_two_id = node_two.node_id
node_one = canvas_node_one.core_node
node_two = canvas_node_two.core_node
# provide a way to get an edge from a core node and an interface id
if src_interface is not None:
self.core_mapping.map_node_and_interface_to_canvas_edge(
node_one_id, src_interface.id, token
# create interfaces
self.interfaces_manager.new_subnet()
interface_one = self.create_edge_interface(canvas_node_one)
if interface_one is not None:
self.interface_to_edge[(node_one.id, interface_one.id)] = token
interface_two = self.create_edge_interface(canvas_node_two)
if interface_two is not None:
self.interface_to_edge[(node_two.id, interface_two.id)] = token
# emane setup
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
)
if dst_interface is not None:
self.core_mapping.map_node_and_interface_to_canvas_edge(
node_two_id, dst_interface.id, token
)
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, dst_interface.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, src_interface.id
)
else:
logging.error("grpcmanagement.py INVALID CANVAS NODE ID")
def get_nodes_proto(self):
nodes = []
for node in self.nodes.values():
pos = core_pb2.Position(x=int(node.x), y=int(node.y))
proto_node = core_pb2.Node(
id=node.node_id, type=node.type, position=pos, model=node.model
)
nodes.append(proto_node)
return nodes
edge = Edge(
self.session_id, node_one.id, node_one.type, node_two.id, node_two.type
)
edge.interface_1 = interface_one
edge.interface_2 = interface_two
self.edges[token] = edge
return edge
def get_links_proto(self):
links = []

View file

@ -1,34 +0,0 @@
"""
provide mapping from core to canvas
"""
import logging
class CoreToCanvasMapping:
def __init__(self):
self.core_id_to_canvas_id = {}
self.core_node_and_interface_to_canvas_edge = {}
def map_node_and_interface_to_canvas_edge(self, nid, iid, edge_token):
self.core_node_and_interface_to_canvas_edge[tuple([nid, iid])] = edge_token
def get_token_from_node_and_interface(self, nid, iid):
key = tuple([nid, iid])
if key in self.core_node_and_interface_to_canvas_edge:
return self.core_node_and_interface_to_canvas_edge[key]
else:
logging.error("invalid key")
return None
def map_core_id_to_canvas_id(self, core_nid, canvas_nid):
if core_nid not in self.core_id_to_canvas_id:
self.core_id_to_canvas_id[core_nid] = canvas_nid
else:
logging.debug("key already existed")
def get_canvas_id_from_core_id(self, core_id):
if core_id in self.core_id_to_canvas_id:
return self.core_id_to_canvas_id[core_id]
else:
logging.debug("invalid key")
return None

View file

@ -21,7 +21,7 @@ class NodeConfigDialog(Dialog):
self.image = canvas_node.image
self.image_button = None
self.name = tk.StringVar(value=canvas_node.name)
self.type = tk.StringVar(value=canvas_node.node_type)
self.type = tk.StringVar(value=canvas_node.core_node.model)
self.server = tk.StringVar()
self.draw()

View file

@ -39,7 +39,8 @@ class CanvasGraph(tk.Canvas):
super().__init__(master, cnf, **kwargs)
self.mode = GraphMode.SELECT
self.draw_node_image = None
self.draw_node_name = None
self.draw_node_type = None
self.draw_node_model = None
self.selected = None
self.node_context = None
self.nodes = {}
@ -97,13 +98,14 @@ class CanvasGraph(tk.Canvas):
# set the private variables to default value
self.mode = GraphMode.SELECT
self.draw_node_image = None
self.draw_node_name = None
self.draw_node_type = None
self.draw_node_model = None
self.selected = None
self.node_context = None
self.nodes.clear()
self.edges.clear()
self.drawing_edge = None
self.draw_existing_component(session)
self.draw_session(session)
def setup_bindings(self):
"""
@ -143,61 +145,46 @@ class CanvasGraph(tk.Canvas):
self.tag_lower("gridline")
self.tag_lower(self.grid)
def draw_existing_component(self, session):
def draw_session(self, session):
"""
Draw existing node and update the information in grpc manager to match
Draw existing session.
:return: nothing
"""
core_id_to_canvas_id = {}
# redraw existing nodes
for node in session.nodes:
# draw existing nodes
for core_node in session.nodes:
# peer to peer node is not drawn on the GUI
if node.type != core_pb2.NodeType.PEER_TO_PEER:
# draw nodes on the canvas
image, name = Images.node_icon(node.type, node.model)
n = CanvasNode(
node.position.x, node.position.y, image, name, self.master, node.id
)
self.nodes[n.id] = n
core_id_to_canvas_id[node.id] = n.id
if core_node.type == core_pb2.NodeType.PEER_TO_PEER:
continue
# store the node in grpc manager
self.core.add_preexisting_node(n, session.id, node, name)
# draw nodes on the canvas
image = Images.node_icon(core_node.type, core_node.model)
position = core_node.position
node = CanvasNode(position.x, position.y, image, self.master, core_node)
self.nodes[node.id] = node
self.core.canvas_nodes[core_node.id] = node
# draw existing links
for link in session.links:
n1 = self.nodes[core_id_to_canvas_id[link.node_one_id]]
n2 = self.nodes[core_id_to_canvas_id[link.node_two_id]]
if link.type == core_pb2.LinkType.WIRED:
e = CanvasEdge(
n1.x_coord,
n1.y_coord,
n2.x_coord,
n2.y_coord,
n1.id,
self,
is_wired=True,
)
elif link.type == core_pb2.LinkType.WIRELESS:
e = CanvasEdge(
n1.x_coord,
n1.y_coord,
n2.x_coord,
n2.y_coord,
n1.id,
self,
is_wired=False,
)
edge_token = tuple(sorted((n1.id, n2.id)))
e.token = edge_token
e.dst = n2.id
n1.edges.add(e)
n2.edges.add(e)
self.edges[e.token] = e
self.core.add_edge(session.id, e.token, n1.id, n2.id)
self.helper.redraw_antenna(link, n1, n2)
canvas_node_one = self.core.canvas_nodes[link.node_one_id]
canvas_node_two = self.core.canvas_nodes[link.node_two_id]
is_wired = link.type == core_pb2.LinkType.WIRED
edge = CanvasEdge(
canvas_node_one.x_coord,
canvas_node_one.y_coord,
canvas_node_two.x_coord,
canvas_node_two.y_coord,
canvas_node_one.id,
self,
is_wired=is_wired,
)
edge.token = tuple(sorted((canvas_node_one.id, canvas_node_two.id)))
edge.dst = canvas_node_two.id
canvas_node_one.edges.add(edge)
canvas_node_two.edges.add(edge)
self.edges[edge.token] = edge
self.core.create_edge(edge.token, canvas_node_one, canvas_node_two)
self.helper.redraw_antenna(link, canvas_node_one, canvas_node_two)
# TODO add back the link info to grpc manager also redraw
grpc_if1 = link.interface_one
@ -212,9 +199,9 @@ class CanvasGraph(tk.Canvas):
if grpc_if2 is not None:
ip4_dst = grpc_if2.ip4
ip6_dst = grpc_if2.ip6
e.link_info = LinkInfo(
edge.link_info = LinkInfo(
canvas=self,
edge=e,
edge=edge,
ip4_src=ip4_src,
ip6_src=ip6_src,
ip4_dst=ip4_dst,
@ -224,14 +211,10 @@ class CanvasGraph(tk.Canvas):
# TODO will include throughput and ipv6 in the future
if1 = Interface(grpc_if1.name, grpc_if1.ip4, ifid=grpc_if1.id)
if2 = Interface(grpc_if2.name, grpc_if2.ip4, ifid=grpc_if2.id)
self.core.edges[e.token].interface_1 = if1
self.core.edges[e.token].interface_2 = if2
self.core.nodes[core_id_to_canvas_id[link.node_one_id]].interfaces.append(
if1
)
self.core.nodes[core_id_to_canvas_id[link.node_two_id]].interfaces.append(
if2
)
self.core.edges[edge.token].interface_1 = if1
self.core.edges[edge.token].interface_2 = if2
canvas_node_one.interfaces.append(if1)
canvas_node_two.interfaces.append(if2)
# raise the nodes so they on top of the links
self.tag_raise("node")
@ -290,7 +273,13 @@ class CanvasGraph(tk.Canvas):
self.handle_edge_release(event)
elif self.mode == GraphMode.NODE:
x, y = self.canvas_xy(event)
self.add_node(x, y, self.draw_node_image, self.draw_node_name)
self.add_node(
x,
y,
self.draw_node_image,
self.draw_node_type,
self.draw_node_model,
)
elif self.mode == GraphMode.PICKNODE:
self.mode = GraphMode.NODE
@ -313,6 +302,7 @@ class CanvasGraph(tk.Canvas):
# edge dst is same as src, delete edge
if edge.src == self.selected:
edge.delete()
return
# set dst node and snap edge to center
x, y = self.coords(self.selected)
@ -326,14 +316,11 @@ class CanvasGraph(tk.Canvas):
node_src.edges.add(edge)
node_dst = self.nodes[edge.dst]
node_dst.edges.add(edge)
self.core.add_edge(
self.core.session_id, edge.token, node_src.id, node_dst.id
)
core_edge = self.core.create_edge(edge.token, node_src, node_dst)
# draw link info on the edge
if1 = self.core.edges[edge.token].interface_1
if2 = self.core.edges[edge.token].interface_2
if1 = core_edge.interface_1
if2 = core_edge.interface_2
ip4_and_prefix_1 = None
ip4_and_prefix_2 = None
if if1 is not None:
@ -404,8 +391,10 @@ class CanvasGraph(tk.Canvas):
)
# delete nodes and link info stored in CanvasGraph object
node_ids = []
for nid in to_delete_nodes:
self.nodes.pop(nid)
canvas_node = self.nodes.pop(nid)
node_ids.append(canvas_node.core_node.id)
for token in to_delete_edge_tokens:
self.edges.pop(token)
@ -419,15 +408,16 @@ class CanvasGraph(tk.Canvas):
self.nodes[nid].edges.remove(edge)
# delete the related data from core
self.core.delete_wanted_graph_nodes(to_delete_nodes, to_delete_edge_tokens)
self.core.delete_wanted_graph_nodes(node_ids, to_delete_edge_tokens)
def add_node(self, x, y, image, node_name):
def add_node(self, x, y, image, node_type, model):
plot_id = self.find_all()[0]
logging.info("add node event: %s - %s", plot_id, self.selected)
if self.selected == plot_id:
node = CanvasNode(x, y, image, node_name, self.master, self.core.peek_id())
core_node = self.core.create_node(int(x), int(y), node_type, model)
node = CanvasNode(x, y, image, self.master, core_node)
self.core.canvas_nodes[core_node.id] = node
self.nodes[node.id] = node
self.core.add_graph_node(self.core.session_id, node.id, x, y, node_name)
return node
def width_and_height(self):
@ -494,7 +484,6 @@ class CanvasGraph(tk.Canvas):
"""
scale image based on canvas dimension
:param Image img: image object
:return: nothing
"""
canvas_w, canvas_h = self.width_and_height()
@ -614,18 +603,17 @@ class CanvasEdge:
class CanvasNode:
def __init__(self, x, y, image, node_type, app, core_id):
def __init__(self, x, y, image, app, core_node):
self.image = image
self.node_type = node_type
self.app = app
self.canvas = app.canvas
self.id = self.canvas.create_image(
x, y, anchor=tk.CENTER, image=self.image, tags="node"
)
self.core_id = core_id
self.core_node = core_node
self.name = core_node.name
self.x_coord = x
self.y_coord = y
self.name = f"N{self.core_id}"
self.text_id = self.canvas.create_text(
x, y + 20, text=self.name, tags="nodename"
)
@ -641,6 +629,7 @@ class CanvasNode:
self.canvas.tag_bind(self.id, "<Leave>", self.on_leave)
self.edges = set()
self.interfaces = []
self.wlans = []
self.moving = None
@ -648,7 +637,7 @@ class CanvasNode:
if self.app.core.is_runtime() and self.app.core.observer:
self.tooltip.text.set("waiting...")
self.tooltip.on_enter(event)
output = self.app.core.run(self.core_id)
output = self.app.core.run(self.core_node.id)
self.tooltip.text.set(output)
def on_leave(self, event):
@ -658,15 +647,15 @@ class CanvasNode:
print("click")
def double_click(self, event):
node_id = self.canvas.core.nodes[self.id].node_id
state = self.canvas.core.get_session_state()
if state == core_pb2.SessionState.RUNTIME:
self.canvas.core.launch_terminal(node_id)
if self.app.core.is_runtime():
self.canvas.core.launch_terminal(self.core_node.id)
else:
self.canvas.canvas_action.display_configuration(self)
def update_coords(self):
self.x_coord, self.y_coord = self.canvas.coords(self.id)
self.core_node.position.x = int(self.x_coord)
self.core_node.position.y = int(self.y_coord)
def click_press(self, event):
logging.debug(f"node click press {self.name}: {event}")
@ -677,7 +666,6 @@ class CanvasNode:
def click_release(self, event):
logging.debug(f"node click release {self.name}: {event}")
self.update_coords()
self.canvas.core.update_node_location(self.id, self.x_coord, self.y_coord)
self.moving = None
def motion(self, event):
@ -697,7 +685,7 @@ class CanvasNode:
new_x, new_y = self.canvas.coords(self.id)
if self.canvas.core.get_session_state() == core_pb2.SessionState.RUNTIME:
self.canvas.core.edit_node(self.core_id, int(new_x), int(new_y))
self.canvas.core.edit_node(self.core_node.id, int(new_x), int(new_y))
for edge in self.edges:
x1, y1, x2, y2 = self.canvas.coords(edge.id)

View file

@ -29,29 +29,31 @@ class GraphHelper:
self.canvas.delete(i)
def draw_wireless_case(self, src_id, dst_id, edge):
src_node_name = self.canvas.nodes[src_id].node_type
dst_node_name = self.canvas.nodes[dst_id].node_type
if src_node_name == "wlan" or dst_node_name == "wlan":
src_node_type = self.canvas.nodes[src_id].core_node.type
dst_node_type = self.canvas.nodes[dst_id].core_node.type
is_src_wlan = src_node_type == core_pb2.NodeType.WIRELESS_LAN
is_dst_wlan = dst_node_type == core_pb2.NodeType.WIRELESS_LAN
if is_src_wlan or is_dst_wlan:
self.canvas.itemconfig(edge.id, state=tk.HIDDEN)
edge.wired = False
if edge.token not in self.canvas.edges:
if src_node_name == "wlan" and dst_node_name == "wlan":
if is_src_wlan and is_dst_wlan:
self.canvas.nodes[src_id].antenna_draw.add_antenna()
elif src_node_name == "wlan":
elif is_src_wlan:
self.canvas.nodes[dst_id].antenna_draw.add_antenna()
else:
self.canvas.nodes[src_id].antenna_draw.add_antenna()
edge.wired = True
def redraw_antenna(self, link, node_one, node_two):
is_node_one_wlan = node_one.core_node.type == core_pb2.NodeType.WIRELESS_LAN
is_node_two_wlan = node_two.core_node.type == core_pb2.NodeType.WIRELESS_LAN
if link.type == core_pb2.LinkType.WIRELESS:
if node_one.node_type == "wlan" and node_two.node_type == "wlan":
if is_node_one_wlan and is_node_two_wlan:
node_one.antenna_draw.add_antenna()
elif node_one.node_type == "wlan" and node_two.node_type != "wlan":
elif is_node_one_wlan and not is_node_two_wlan:
node_two.antenna_draw.add_antenna()
elif node_one.node_type != "wlan" and node_two.node_type == "wlan":
elif not is_node_one_wlan and is_node_two_wlan:
node_one.antenna_draw.add_antenna()
else:
logging.error(
@ -122,91 +124,3 @@ class WlanAntennaManager:
"""
for i in self.antennas:
self.canvas.delete(i)
# class WlanConnection:
# def __init__(self, canvas, grpc):
# """
# create in
# :param canvas:
# """
# self.canvas = canvas
# self.core_grpc = grpc
# self.throughput_on = False
# self.map_node_link = {}
# self.links = []
#
# def wireless_nodes(self):
# """
# retrieve all the wireless clouds in the canvas
#
# :return: list(coretk.graph.CanvasNode)
# """
# wireless_nodes = []
# for n in self.canvas.nodes.values():
# if n.node_type == "wlan":
# wireless_nodes.append(n)
# return wireless_nodes
#
# def draw_wireless_link(self, src, dst):
# """
# draw a line between 2 nodes that are connected to the same wireless cloud
#
# :param coretk.graph.CanvasNode src: source node
# :param coretk.graph.CanvasNode dst: destination node
# :return: nothing
# """
# cid = self.canvas.create_line(src.x_coord, src.y_coord, dst.x_coord, dst.y_coord, tags="wlanconnection")
# if src.id not in self.map_node_link:
# self.map_node_link[src.id] = []
# if dst.id not in self.map_node_link:
# self.map_node_link[dst.id] = []
# self.map_node_link[src.id].append(cid)
# self.map_node_link[dst.id].append(cid)
# self.links.append(cid)
#
# def subnet_wireless_connection(self, wlan_node):
# """
# retrieve all the non-wireless nodes connected to wireless_node and create line (represent wireless connection) between each pair of nodes
# :param coretk.grpah.CanvasNode wlan_node: wireless node
#
# :return: nothing
# """
# non_wlan_nodes = []
# for e in wlan_node.edges:
# src = self.canvas.nodes[e.src]
# dst = self.canvas.nodes[e.dst]
# if src.node_type == "wlan" and dst.node_type != "wlan":
# non_wlan_nodes.append(dst)
# elif src.node_type != "wlan" and dst.node_type == "wlan":
# non_wlan_nodes.append(src)
#
# size = len(non_wlan_nodes)
# for i in range(size):
# for j in range(i+1, size):
# self.draw_wireless_link(non_wlan_nodes[i], non_wlan_nodes[j])
#
# def session_wireless_connection(self):
# """
# draw all the wireless connection in the canvas
#
# :return: nothing
# """
# wlan_nodes = self.wireless_nodes()
# for n in wlan_nodes:
# self.subnet_wireless_connection(n)
#
# def show_links(self):
# """
# show all the links
# """
# for l in self.links:
# self.canvas.itemconfig(l, state=tk.NORMAL)
#
# def hide_links(self):
# """
# hide all the links
# :return:
# """
# for l in self.links:
# self.canvas.itemconfig(l, state=tk.HIDDEN)

View file

@ -31,7 +31,7 @@ class Images:
return cls.create(file_path, width, height)
@classmethod
def get_custom(cls, name, width, height):
def get_custom(cls, name, width, height=None):
file_path = cls.images[name]
return cls.create(file_path, width, height)
@ -41,52 +41,38 @@ class Images:
Retrieve image based on type and model
:param core_pb2.NodeType node_type: core node type
:param string node_model: the node model
:rtype: tuple(PhotoImage, str)
:return: the matching image and its name
:return: core node icon
:rtype: PhotoImage
"""
image_enum = ImageEnum.ROUTER
name = "unknown"
if node_type == core_pb2.NodeType.SWITCH:
image_enum = ImageEnum.SWITCH
name = "switch"
elif node_type == core_pb2.NodeType.HUB:
image_enum = ImageEnum.HUB
name = "hub"
elif node_type == core_pb2.NodeType.WIRELESS_LAN:
image_enum = ImageEnum.WLAN
name = "wlan"
elif node_type == core_pb2.NodeType.EMANE:
image_enum = ImageEnum.EMANE
name = "emane"
elif node_type == core_pb2.NodeType.RJ45:
image_enum = ImageEnum.RJ45
name = "rj45"
elif node_type == core_pb2.NodeType.TUNNEL:
image_enum = ImageEnum.TUNNEL
name = "tunnel"
elif node_type == core_pb2.NodeType.DEFAULT:
if node_model == "router":
image_enum = ImageEnum.ROUTER
name = "router"
elif node_model == "host":
image_enum = ImageEnum.HOST
name = "host"
elif node_model == "PC":
image_enum = ImageEnum.PC
name = "PC"
elif node_model == "mdr":
image_enum = ImageEnum.MDR
name = "mdr"
elif node_model == "prouter":
image_enum = ImageEnum.PROUTER
name = "prouter"
else:
logging.error("invalid node model: %s", node_model)
else:
logging.error("invalid node type: %s", node_type)
return Images.get(image_enum, NODE_WIDTH), name
return Images.get(image_enum, NODE_WIDTH)
class ImageEnum(Enum):

View file

@ -129,8 +129,7 @@ class Throughput:
nid = t.node_id
iid = t.interface_id
tp = t.throughput
# token = self.grpc_manager.node_id_and_interface_to_edge_token[nid, iid]
token = self.core.core_mapping.get_token_from_node_and_interface(nid, iid)
token = self.core.interface_to_edge[(nid, iid)]
print(token)
edge_id = self.canvas.edges[token].id

View file

@ -3,6 +3,7 @@ import tkinter as tk
from functools import partial
from tkinter import ttk
from core.api.grpc import core_pb2
from coretk.dialogs.customnodes import CustomNodesDialog
from coretk.graph import GraphMode
from coretk.images import ImageEnum, Images
@ -136,10 +137,16 @@ class Toolbar(ttk.Frame):
(ImageEnum.PROUTER, "prouter"),
]
# draw default nodes
for image_enum, tooltip in nodes:
for image_enum, model in nodes:
image = icon(image_enum)
func = partial(self.update_button, self.node_button, image, tooltip)
self.create_picker_button(image, func, self.node_picker, tooltip)
func = partial(
self.update_button,
self.node_button,
image,
core_pb2.NodeType.DEFAULT,
model,
)
self.create_picker_button(image, func, self.node_picker, model)
# draw custom nodes
for name in sorted(self.app.core.custom_nodes):
custom_node = self.app.core.custom_nodes[name]
@ -216,14 +223,15 @@ class Toolbar(ttk.Frame):
dialog = CustomNodesDialog(self.app, self.app)
dialog.show()
def update_button(self, button, image, name):
logging.info("update button(%s): %s", button, name)
def update_button(self, button, image, node_type, model=None):
logging.info("update button(%s): %s", button, node_type)
self.hide_pickers()
button.configure(image=image)
button.image = image
self.app.canvas.mode = GraphMode.NODE
self.app.canvas.draw_node_image = image
self.app.canvas.draw_node_name = name
self.app.canvas.draw_node_type = node_type
self.app.canvas.draw_node_model = model
def hide_pickers(self):
logging.info("hiding pickers")
@ -260,18 +268,18 @@ class Toolbar(ttk.Frame):
self.hide_pickers()
self.network_picker = ttk.Frame(self.master)
nodes = [
(ImageEnum.HUB, "hub", "ethernet hub"),
(ImageEnum.SWITCH, "switch", "ethernet switch"),
(ImageEnum.WLAN, "wlan", "wireless LAN"),
(ImageEnum.EMANE, "emane", "EMANE"),
(ImageEnum.RJ45, "rj45", "rj45 physical interface tool"),
(ImageEnum.TUNNEL, "tunnel", "tunnel tool"),
(ImageEnum.HUB, core_pb2.NodeType.HUB, "ethernet hub"),
(ImageEnum.SWITCH, core_pb2.NodeType.SWITCH, "ethernet switch"),
(ImageEnum.WLAN, core_pb2.NodeType.WIRELESS_LAN, "wireless LAN"),
(ImageEnum.EMANE, core_pb2.NodeType.EMANE, "EMANE"),
(ImageEnum.RJ45, core_pb2.NodeType.RJ45, "rj45 physical interface tool"),
(ImageEnum.TUNNEL, core_pb2.NodeType.TUNNEL, "tunnel tool"),
]
for image_enum, name, tooltip in nodes:
for image_enum, node_type, tooltip in nodes:
image = icon(image_enum)
self.create_picker_button(
image,
partial(self.update_button, self.network_button, image, name),
partial(self.update_button, self.network_button, image, node_type),
self.network_picker,
tooltip,
)

View file

@ -7,35 +7,31 @@ from core.api.grpc import core_pb2
class WirelessConnection:
def __init__(self, canvas, core):
self.canvas = canvas
self.core_mapping = core.core_mapping
self.core = core
# map a (node_one_id, node_two_id) to a wlan canvas id
self.map = {}
def add_wlan_connection(self, node_one_id, node_two_id):
canvas_id_one = self.core_mapping.get_canvas_id_from_core_id(node_one_id)
canvas_id_two = self.core_mapping.get_canvas_id_from_core_id(node_two_id)
canvas_node_one = self.core.canvas_nodes[node_one_id]
canvas_node_two = self.core.canvas_nodes[node_two_id]
key = tuple(sorted((node_one_id, node_two_id)))
if key not in self.map:
x1, y1 = self.canvas.coords(canvas_id_one)
x2, y2 = self.canvas.coords(canvas_id_two)
x1, y1 = self.canvas.coords(canvas_node_one.id)
x2, y2 = self.canvas.coords(canvas_node_two.id)
wlan_canvas_id = self.canvas.create_line(
x1, y1, x2, y2, fill="#009933", tags="wlan", width=1.5
)
self.map[key] = wlan_canvas_id
self.canvas.nodes[canvas_id_one].wlans.append(wlan_canvas_id)
self.canvas.nodes[canvas_id_two].wlans.append(wlan_canvas_id)
canvas_node_one.wlans.append(wlan_canvas_id)
canvas_node_two.wlans.append(wlan_canvas_id)
def delete_wlan_connection(self, node_one_id, node_two_id):
canvas_id_one = self.core_mapping.get_canvas_id_from_core_id(node_one_id)
canvas_id_two = self.core_mapping.get_canvas_id_from_core_id(node_two_id)
canvas_node_one = self.core.canvas_nodes[node_one_id]
canvas_node_two = self.core.canvas_nodes[node_two_id]
key = tuple(sorted((node_one_id, node_two_id)))
wlan_canvas_id = self.map[key]
self.canvas.nodes[canvas_id_one].wlans.remove(wlan_canvas_id)
self.canvas.nodes[canvas_id_two].wlans.remove(wlan_canvas_id)
canvas_node_one.wlans.remove(wlan_canvas_id)
canvas_node_two.wlans.remove(wlan_canvas_id)
self.canvas.delete(wlan_canvas_id)
self.map.pop(key, None)