some work on grpc add nodes and links, some work on query session, redraw nodes

This commit is contained in:
Huy Pham 2019-10-03 16:50:49 -07:00
parent cbd593eed6
commit cb03aa261a
6 changed files with 387 additions and 137 deletions

View file

@ -16,16 +16,20 @@ class Application(tk.Frame):
self.setup_app()
self.menubar = None
self.canvas = None
# start grpc
self.core_grpc = CoreGrpc()
self.create_menu()
self.create_widgets()
def load_images(self):
"""
Load core images
:return:
"""
images.load_core_images(Images)
def close_grpc(self):
self.core_grpc.close()
def setup_app(self):
self.master.title("CORE")
self.master.geometry("1000x800")
@ -47,8 +51,8 @@ class Application(tk.Frame):
core_editbar.create_toolbar()
self.canvas = CanvasGraph(
grpc=self.core_grpc,
master=self,
grpc=self.core_grpc,
background="#cccccc",
scrollregion=(0, 0, 1000, 1000),
)
@ -79,4 +83,3 @@ if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
app = Application()
app.mainloop()
app.close_grpc()

View file

@ -14,18 +14,20 @@ class CoreGrpc:
self.core = client.CoreGrpcClient()
self.session_id = None
self.set_up()
self.interface_helper = None
def log_event(self, event):
logging.info("event: %s", event)
def set_up(self):
def redraw_canvas(self):
return
def create_new_session(self):
"""
Create session, handle events session may broadcast, change session state
Create a new session
:return: nothing
"""
self.core.connect()
# create session
response = self.core.create_session()
logging.info("created session: %s", response)
@ -33,39 +35,67 @@ class CoreGrpc:
self.session_id = response.session_id
self.core.events(self.session_id, self.log_event)
# change session state
def query_existing_sessions(self, sessions):
"""
Query for existing sessions and prompt to join one
:param repeated core_pb2.SessionSummary sessions: summaries of all the existing sessions
:return: nothing
"""
for session in sessions:
logging.info("Session id: %s, Session state: %s", session.id, session.state)
logging.info("Input a session you want to enter from the keyboard:")
usr_input = int(input())
if usr_input == 0:
self.create_new_session()
else:
response = self.core.get_session(usr_input)
self.session_id = usr_input
# self.core.events(self.session_id, self.log_event)
logging.info("Entering session_id %s.... Result: %s", usr_input, response)
def set_up(self):
"""
Query sessions, if there exist any, promt whether to join one
:return: nothing
"""
self.core.connect()
response = self.core.get_sessions()
logging.info("all sessions: %s", response)
# if there are no sessions, create a new session, else join a session
sessions = response.sessions
if len(sessions) == 0:
self.create_new_session()
else:
# self.create_new_session()
self.query_existing_sessions(sessions)
def set_configuration_state(self):
response = self.core.set_session_state(
self.session_id, core_pb2.SessionState.CONFIGURATION
)
logging.info("set session state: %s", response)
def set_instantiate_state(self):
response = self.core.set_session_state(
self.session_id, core_pb2.SessionState.INSTANTIATION
)
logging.info("set session state: %s", response)
def get_session_id(self):
return self.session_id
# TODO add checkings to the function
def add_node(self, x, y, node_name):
link_layer_nodes = ["switch", "hub", "wlan", "rj45", "tunnel"]
network_layer_nodes = ["default"]
node = None
if node_name in link_layer_nodes:
if node_name == "switch":
node = core_pb2.Node(type=core_pb2.NodeType.SWITCH)
elif node_name == "hub":
node = core_pb2.Node(type=core_pb2.NodeType.HUB)
elif node_name == "wlan":
node = core_pb2.Node(type=core_pb2.NodeType.WIRELESS_LAN)
elif node_name == "rj45":
node = core_pb2.Node(type=core_pb2.NodeType.RJ45)
elif node_name == "tunnel":
node = core_pb2.Node(type=core_pb2.NodeType.TUNNEL)
elif node_name in network_layer_nodes:
def add_node(self, node_type, model, x, y, name):
logging.info("ADD NODE %s", name)
position = core_pb2.Position(x=x, y=y)
node = core_pb2.Node(position=position)
else:
return
node = core_pb2.Node(type=node_type, position=position, model=model, image=name)
response = self.core.add_node(self.session_id, node)
logging.info("created %s: %s", node_name, response)
logging.info("created node: %s", response)
return response.node_id
def edit_node(self, session_id, node_id, x, y):
@ -73,6 +103,34 @@ class CoreGrpc:
response = self.core.edit_node(session_id, node_id, position)
logging.info("updated node id %s: %s", node_id, response)
# def create_interface_helper(self):
# self.interface_helper = self.core.InterfaceHelper(ip4_prefix="10.83.0.0/16")
# TODO case for other core_pb2.NodeType
def add_link(self, id1, id2, type1, type2):
"""
Grpc client request add link
:param int session_id: session id
:param int id1: node 1 core id
:param core_pb2.NodeType type1: node 1 core node type
:param int id2: node 2 core id
:param core_pb2.NodeType type2: node 2 core node type
:return: nothing
"""
if not self.interface_helper:
logging.debug("INTERFACE HELPER NOT CREATED YET, CREATING ONE...")
self.interface_helper = client.InterfaceHelper(ip4_prefix="10.83.0.0/16")
interface1 = None
interface2 = None
if type1 == core_pb2.NodeType.DEFAULT:
interface1 = self.interface_helper.create_interface(id1, 0)
if type2 == core_pb2.NodeType.DEFAULT:
interface2 = self.interface_helper.create_interface(id2, 0)
response = self.core.add_link(self.session_id, id1, id2, interface1, interface2)
logging.info("created link: %s", response)
def close(self):
"""
Clean ups when done using grpc

View file

@ -27,7 +27,6 @@ class CoreToolbar(object):
self.width = 32
self.height = 32
# Used for drawing the horizontally displayed menu items for network-layer nodes and link-layer node
self.selection_tool_button = None
# Reference to the option menus
@ -35,8 +34,6 @@ class CoreToolbar(object):
self.marker_option_menu = None
self.network_layer_option_menu = None
# variables used by canvas graph
self.image_to_draw = None
self.canvas = None
def update_canvas(self, canvas):
@ -151,63 +148,79 @@ class CoreToolbar(object):
logging.debug("Click SELECTION TOOL")
self.canvas.mode = GraphMode.SELECT
def click_start_stop_session_tool(self):
def click_start_session_tool(self):
logging.debug("Click START STOP SESSION button")
self.destroy_children_widgets(self.edit_frame)
self.canvas.set_canvas_mode(GraphMode.SELECT)
self.canvas.mode = GraphMode.SELECT
self.create_runtime_toolbar()
# set configuration state
self.canvas.core_grpc.set_configuration_state()
# grpc client requests creating nodes
for node in self.canvas.grpc_manager.nodes_to_create.values():
self.canvas.core_grpc.add_node(
node.type, node.model, int(node.x), int(node.y), node.name
)
self.canvas.grpc_manager.nodes_to_create.clear()
for edge in self.canvas.grpc_manager.edges_to_create.values():
self.canvas.core_grpc.add_link(edge.id1, edge.id2, edge.type1, edge.type2)
self.canvas.grpc_manager.edges_to_create.clear()
self.canvas.core_grpc.set_instantiate_state()
def click_link_tool(self):
logging.debug("Click LINK button")
self.canvas.set_canvas_mode(GraphMode.EDGE)
self.canvas.mode = GraphMode.EDGE
def pick_router(self, main_button):
logging.debug("Pick router option")
self.network_layer_option_menu.destroy()
main_button.configure(image=Images.get("router"))
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
self.canvas.set_drawing_image(Images.get("router"))
self.canvas.set_drawing_name("default")
self.canvas.mode = GraphMode.PICKNODE
self.canvas.draw_node_image = Images.get("router")
self.canvas.draw_node_name = "router"
def pick_host(self, main_button):
logging.debug("Pick host option")
self.network_layer_option_menu.destroy()
main_button.configure(image=Images.get("host"))
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
self.canvas.set_drawing_image(Images.get("host"))
self.canvas.set_drawing_name("default")
self.canvas.mode = GraphMode.PICKNODE
self.canvas.draw_node_image = Images.get("host")
self.canvas.draw_node_name = "host"
def pick_pc(self, main_button):
logging.debug("Pick PC option")
self.network_layer_option_menu.destroy()
main_button.configure(image=Images.get("pc"))
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
self.canvas.set_drawing_image(Images.get("pc"))
self.canvas.set_drawing_name("default")
self.canvas.mode = GraphMode.PICKNODE
self.canvas.draw_node_image = Images.get("pc")
self.canvas.draw_node_name = "PC"
def pick_mdr(self, main_button):
logging.debug("Pick MDR option")
self.network_layer_option_menu.destroy()
main_button.configure(image=Images.get("mdr"))
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
self.canvas.set_drawing_image(Images.get("mdr"))
self.canvas.set_drawing_name("default")
self.canvas.mode = GraphMode.PICKNODE
self.canvas.draw_node_image = Images.get("mdr")
self.canvas.draw_node_name = "mdr"
def pick_prouter(self, main_button):
logging.debug("Pick prouter option")
self.network_layer_option_menu.destroy()
main_button.configure(image=Images.get("prouter"))
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
self.canvas.set_drawing_image(Images.get("prouter"))
self.canvas.set_drawing_name("default")
self.canvas.mode = GraphMode.PICKNODE
self.canvas.draw_node_image = Images.get("prouter")
self.canvas.draw_node_name = "prouter"
def pick_ovs(self, main_button):
logging.debug("Pick OVS option")
self.network_layer_option_menu.destroy()
main_button.configure(image=Images.get("ovs"))
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
self.canvas.set_drawing_image(Images.get("ovs"))
self.canvas.set_drawing_name("default")
self.canvas.mode = GraphMode.PICKNODE
self.canvas.draw_node_image = Images.get("ovs")
self.canvas.draw_node_name = "OVS"
# TODO what graph node is this
def pick_editnode(self, main_button):
@ -294,40 +307,41 @@ class CoreToolbar(object):
logging.debug("Pick link-layer node HUB")
self.link_layer_option_menu.destroy()
main_button.configure(image=Images.get("hub"))
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
self.canvas.set_drawing_image(Images.get("hub"))
self.canvas.set_drawing_name("hub")
self.canvas.mode = GraphMode.PICKNODE
self.canvas.draw_node_image = Images.get("hub")
self.canvas.draw_node_name = "hub"
def pick_switch(self, main_button):
logging.debug("Pick link-layer node SWITCH")
self.link_layer_option_menu.destroy()
main_button.configure(image=Images.get("switch"))
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
self.canvas.set_drawing_image(Images.get("switch"))
self.canvas.set_drawing_name("switch")
self.canvas.mode = GraphMode.PICKNODE
self.canvas.draw_node_image = Images.get("switch")
self.canvas.draw_node_name = "switch"
def pick_wlan(self, main_button):
logging.debug("Pick link-layer node WLAN")
self.link_layer_option_menu.destroy()
main_button.configure(image=Images.get("wlan"))
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
self.canvas.set_drawing_image(Images.get("wlan"))
self.canvas.set_drawing_name("wlan")
self.canvas.mode = GraphMode.PICKNODE
self.canvas.draw_node_image = Images.get("wlan")
self.canvas.draw_node_name = "wlan"
def pick_rj45(self, main_button):
logging.debug("Pick link-layer node RJ45")
self.link_layer_option_menu.destroy()
main_button.configure(image=Images.get("rj45"))
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
self.canvas.set_drawing_image(Images.get("rj45"))
self.canvas.mode = GraphMode.PICKNODE
self.canvas.draw_node_image = Images.get("rj45")
self.canvas.draw_node_name = "rj45"
def pick_tunnel(self, main_button):
logging.debug("Pick link-layer node TUNNEL")
self.link_layer_option_menu.destroy()
main_button.configure(image=Images.get("tunnel"))
self.canvas.set_canvas_mode(GraphMode.PICKNODE)
self.canvas.set_drawing_image(Images.get("tunnel"))
self.canvas.set_drawing_image(Images.get("tunnel"))
self.canvas.mode = GraphMode.PICKNODE
self.canvas.draw_node_image = Images.get("tunnel")
self.canvas.draw_node_name = "tunnel"
def draw_link_layer_options(self, link_layer_button):
"""
@ -476,11 +490,10 @@ class CoreToolbar(object):
CreateToolTip(marker_main_button, "background annotation tools")
def create_toolbar(self):
# self.load_toolbar_images()
self.create_regular_button(
self.edit_frame,
Images.get("start"),
self.click_start_stop_session_tool,
self.click_start_session_tool,
"start the session",
)
self.create_radio_button(

View file

@ -2,6 +2,9 @@ import enum
import logging
import tkinter as tk
from coretk.grpcmanagement import GrpcManager
from coretk.images import Images
class GraphMode(enum.Enum):
SELECT = 0
@ -12,12 +15,11 @@ class GraphMode(enum.Enum):
class CanvasGraph(tk.Canvas):
def __init__(self, grpc=None, master=None, cnf=None, **kwargs):
def __init__(self, master=None, grpc=None, cnf=None, **kwargs):
if cnf is None:
cnf = {}
kwargs["highlightthickness"] = 0
super().__init__(master, cnf, **kwargs)
self.core_grpc = grpc
self.mode = GraphMode.SELECT
self.draw_node_image = None
self.draw_node_name = None
@ -26,19 +28,32 @@ class CanvasGraph(tk.Canvas):
self.nodes = {}
self.edges = {}
self.drawing_edge = None
self.setup_menus()
self.setup_bindings()
self.draw_grid()
self.core_grpc = grpc
self.grpc_manager = GrpcManager()
self.draw_existing_node()
def set_canvas_mode(self, mode):
self.mode = mode
def setup_menus(self):
self.node_context = tk.Menu(self.master)
self.node_context.add_command(label="One")
self.node_context.add_command(label="Two")
self.node_context.add_command(label="Three")
def set_drawing_image(self, img):
self.draw_node_image = img
def setup_bindings(self):
"""
Bind any mouse events or hot keys to the matching action
def set_drawing_name(self, name):
self.draw_node_name = name
:return: nothing
"""
self.bind("<ButtonPress-1>", self.click_press)
self.bind("<ButtonRelease-1>", self.click_release)
self.bind("<B1-Motion>", self.click_motion)
self.bind("<Button-3>", self.context)
# self.bind("e", self.set_mode)
# self.bind("s", self.set_mode)
# self.bind("n", self.set_mode)
def draw_grid(self, width=1000, height=750):
"""
@ -65,25 +80,20 @@ class CanvasGraph(tk.Canvas):
for i in range(0, height, 27):
self.create_line(0, i, width, i, dash=(2, 4), tags="grid line")
def setup_menus(self):
self.node_context = tk.Menu(self.master)
self.node_context.add_command(label="One")
self.node_context.add_command(label="Two")
self.node_context.add_command(label="Three")
def setup_bindings(self):
def draw_existing_node(self):
"""
Bind any mouse events or hot keys to the matching action
Draw existing node while updating the grpc manager based on that
:return: nothing
"""
self.bind("<ButtonPress-1>", self.click_press)
self.bind("<ButtonRelease-1>", self.click_release)
self.bind("<B1-Motion>", self.click_motion)
self.bind("<Button-3>", self.context)
# self.bind("e", self.set_mode)
# self.bind("s", self.set_mode)
# self.bind("n", self.set_mode)
session_id = self.core_grpc.session_id
response = self.core_grpc.core.get_session(session_id)
nodes = response.session.nodes
if len(nodes) > 0:
for node in nodes:
image = Images.convert_type_and_model_to_image(node.type, node.model)
return image
# n = CanvasNode(node.position.x, node.position.y, image, self, node.id)
def canvas_xy(self, event):
"""
@ -172,6 +182,10 @@ class CanvasGraph(tk.Canvas):
node_dst = self.nodes[edge.dst]
node_dst.edges.add(edge)
self.grpc_manager.add_edge(
self.core_grpc.get_session_id(), edge.token, node_src.id, node_dst.id
)
logging.debug(f"edges: {self.find_withtag('edge')}")
def click_press(self, event):
@ -207,40 +221,14 @@ class CanvasGraph(tk.Canvas):
logging.debug(f"node context: {selected}")
self.node_context.post(event.x_root, event.y_root)
# def set_mode(self, event):
# """
# Set canvas mode according to the hot key that has been pressed
#
# :param event: key event
# :return: nothing
# """
# logging.debug(f"mode event: {event}")
# if event.char == "e":
# self.mode = GraphMode.EDGE
# elif event.char == "s":
# self.mode = GraphMode.SELECT
# elif event.char == "n":
# self.mode = GraphMode.NODE
# logging.debug(f"graph mode: {self.mode}")
# def add_node(self, x, y, image_name):
# image = Images.get(image_name)
# node = CanvasNode(x, y, image, self)
# self.nodes[node.id] = node
# return node
def add_node(self, x, y, image, node_name):
core_session_id = self.core_grpc.get_session_id()
core_node_id = self.core_grpc.add_node(int(x), int(y), node_name)
node = CanvasNode(
core_session_id=core_session_id,
core_node_id=core_node_id,
x=x,
y=y,
image=image,
canvas=self,
x=x, y=y, image=image, canvas=self, core_id=self.grpc_manager.peek_id()
)
self.nodes[node.id] = node
self.grpc_manager.add_node(
self.core_grpc.get_session_id(), node.id, x, y, node_name
)
return node
@ -283,17 +271,16 @@ class CanvasEdge:
class CanvasNode:
def __init__(self, core_session_id, core_node_id, x, y, image, canvas):
def __init__(self, x, y, image, canvas, core_id):
self.image = image
self.canvas = canvas
self.id = self.canvas.create_image(
x, y, anchor=tk.CENTER, image=self.image, tags="node"
)
self.core_id = core_id
self.x_coord = x
self.y_coord = y
self.core_session_id = core_session_id
self.core_node_id = core_node_id
self.name = f"Node {self.core_node_id}"
self.name = f"Node {self.core_id}"
self.text_id = self.canvas.create_text(x, y + 20, text=self.name)
self.canvas.tag_bind(self.id, "<ButtonPress-1>", self.click_press)
self.canvas.tag_bind(self.id, "<ButtonRelease-1>", self.click_release)
@ -315,12 +302,6 @@ class CanvasNode:
def click_release(self, event):
logging.debug(f"click release {self.name}: {event}")
self.update_coords()
self.canvas.core_grpc.edit_node(
self.core_session_id,
self.core_node_id,
int(self.x_coord),
int(self.y_coord),
)
self.moving = None
def motion(self, event):

View file

@ -0,0 +1,157 @@
"""
Manage useful informations about the nodes, edges and configuration
that can be useful for grpc, acts like a session class
"""
import logging
from core.api.grpc import core_pb2
link_layer_nodes = ["switch", "hub", "wlan", "rj45", "tunnel"]
network_layer_nodes = ["router", "host", "PC", "mdr", "prouter", "OVS"]
class Node:
def __init__(self, session_id, node_id, 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 type: node type
:param int x: x coordinate
:param int y: coordinate
"""
self.session_id = session_id
self.node_id = node_id
self.type = type
self.x = x
self.y = y
self.model = model
self.name = name
class Edge:
def __init__(self, session_id, node_id_1, node_type_1, node_id_2, node_type_2):
"""
Create an instance of an edge
:param int session_id: session id
:param int node_id_1: node 1 id
:param int node_type_1: node 1 type
:param core_pb2.NodeType node_id_2: node 2 id
:param core_pb2.NodeType node_type_2: node 2 type
"""
self.session_id = session_id
self.id1 = node_id_1
self.id2 = node_id_2
self.type1 = node_type_1
self.type2 = node_type_2
class GrpcManager:
def __init__(self):
self.nodes = {}
self.edges = {}
self.id = 1
# A list of id for re-use, keep in increasing order
self.reusable = []
self.nodes_to_create = {}
self.edges_to_create = {}
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
:rtype: int
:return: the next id to be used
"""
if len(self.reusable) == 0:
new_id = self.id
self.id = self.id + 1
return new_id
else:
return self.reusable.pop(0)
# TODO figure out the name of ovs node
def add_node(self, session_id, canvas_id, x, y, name):
"""
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
:return: nothing
"""
node_type = None
node_model = None
if name in link_layer_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 == "tunnel":
node_type = core_pb2.NodeType.TUNNEL
elif name in network_layer_nodes:
node_type = core_pb2.NodeType.DEFAULT
# TODO what is the model name for ovs
node_model = name
else:
logging.error("grpcmanagemeny.py INVALID node name")
create_node = Node(session_id, self.get_id(), node_type, node_model, x, y, name)
self.nodes[canvas_id] = create_node
self.nodes_to_create[canvas_id] = create_node
logging.debug(
"Adding node to GrpcManager.. Session id: %s, Coords: (%s, %s), Name: %s",
session_id,
x,
y,
name,
)
def add_preexisting_node(self):
return
def delete_node(self, canvas_id):
"""
Delete a node from the session
:param int canvas_id: node's id in the canvas
:return: thing
"""
try:
self.nodes.pop(canvas_id)
self.reuseable.append(canvas_id)
self.reuseable.sort()
except KeyError:
logging.error("grpcmanagement.py INVALID NODE CANVAS ID")
def add_edge(self, session_id, token, canvas_id_1, canvas_id_2):
if canvas_id_1 in self.nodes and canvas_id_2 in self.nodes:
edge = Edge(
session_id,
self.nodes[canvas_id_1].node_id,
self.nodes[canvas_id_1].type,
self.nodes[canvas_id_2].node_id,
self.nodes[canvas_id_2].type,
)
self.edges[token] = edge
self.edges_to_create[token] = edge
logging.debug("Adding edge to grpc manager...")
else:
logging.error("grpcmanagement.py INVALID CANVAS NODE ID")

View file

@ -1,7 +1,10 @@
import logging
import os
from PIL import Image, ImageTk
from core.api.grpc import core_pb2
PATH = os.path.abspath(os.path.dirname(__file__))
@ -19,6 +22,41 @@ class Images:
def get(cls, name):
return cls.images[name]
@classmethod
def convert_type_and_model_to_image(cls, node_type, node_model):
"""
Retrieve image based on type and model
:param core_pb2.NodeType node_type: core node type
:param string node_model: the node model
:return: the matching image
"""
if node_type == core_pb2.NodeType.SWITCH:
return Images.get("switch")
if node_type == core_pb2.NodeType.HUB:
return Images.get("hub")
if node_type == core_pb2.NodeType.WIRELESS_LAN:
return Images.get("wlan")
if node_type == core_pb2.NodeType.RJ45:
return Images.get("rj45")
if node_type == core_pb2.NodeType.TUNNEL:
return Images.get("tunnel")
if node_type == core_pb2.NodeType.DEFAULT:
if node_model == "router":
return Images.get("router")
if node_model == "host":
return Images.get(("host"))
if node_model == "PC":
return Images.get("pc")
if node_model == "mdr":
return Images.get("mdr")
if node_model == "prouter":
return Images.get("prouter")
if node_model == "OVS":
return Images.get("ovs")
else:
logging.debug("INVALID INPUT OR NOT CONSIDERED YET")
def load_core_images(images):
images.load("core", "core-icon.png")