deleting node also deletes antenna

This commit is contained in:
Huy Pham 2019-11-25 14:09:41 -08:00
commit 4d3bde7c31
5 changed files with 176 additions and 172 deletions

View file

@ -57,27 +57,49 @@ class CoreClient:
self.custom_observers = {} self.custom_observers = {}
self.read_config() self.read_config()
# data for managing the current session # helpers
self.canvas_nodes = {}
self.location = None
self.interface_to_edge = {} self.interface_to_edge = {}
self.state = None
self.links = {}
self.hooks = {}
self.id = 1
self.reusable = [] self.reusable = []
self.preexisting = set() self.preexisting = set()
self.interfaces_manager = InterfaceManager(self.app) self.interfaces_manager = InterfaceManager(self.app)
self.created_nodes = set()
self.created_links = set()
# session data
self.id = 1
self.state = None
self.canvas_nodes = {}
self.location = None
self.links = {}
self.hooks = {}
self.wlan_configs = {} self.wlan_configs = {}
self.mobility_configs = {} self.mobility_configs = {}
self.emane_model_configs = {} self.emane_model_configs = {}
self.emane_config = None self.emane_config = None
self.created_nodes = set()
self.created_links = set()
self.service_configs = {} self.service_configs = {}
self.file_configs = {} self.file_configs = {}
def reset(self):
self.id = 1
# helpers
self.created_nodes.clear()
self.created_links.clear()
self.reusable.clear()
self.preexisting.clear()
self.interfaces_manager.reset()
self.interface_to_edge.clear()
# session data
self.canvas_nodes.clear()
self.location = None
self.links.clear()
self.hooks.clear()
self.wlan_configs.clear()
self.mobility_configs.clear()
self.emane_model_configs.clear()
self.emane_config = None
self.service_configs.clear()
self.file_configs.clear()
def set_observer(self, value): def set_observer(self, value):
self.observer = value self.observer = value
@ -130,16 +152,7 @@ class CoreClient:
self.master.title(f"CORE Session({self.session_id})") self.master.title(f"CORE Session({self.session_id})")
# clear session data # clear session data
self.reusable.clear() self.reset()
self.preexisting.clear()
self.canvas_nodes.clear()
self.links.clear()
self.hooks.clear()
self.wlan_configs.clear()
self.mobility_configs.clear()
self.emane_config = None
self.service_configs.clear()
self.file_configs.clear()
# get session data # get session data
response = self.client.get_session(self.session_id) response = self.client.get_session(self.session_id)
@ -224,29 +237,12 @@ class CoreClient:
) )
self.join_session(response.session_id, query_location=False) self.join_session(response.session_id, query_location=False)
def delete_session(self, custom_sid=None): def delete_session(self, session_id=None):
if custom_sid is None: if session_id is None:
sid = self.session_id session_id = self.session_id
else: response = self.client.delete_session(session_id)
sid = custom_sid
response = self.client.delete_session(sid)
logging.info("Deleted session result: %s", response) logging.info("Deleted session result: %s", response)
def shutdown_session(self, custom_sid=None):
if custom_sid is None:
sid = self.session_id
else:
sid = custom_sid
s = self.client.get_session(sid).session
# delete links and nodes from running session
if s.state == core_pb2.SessionState.RUNTIME:
self.client.set_session_state(
self.session_id, core_pb2.SessionState.DATACOLLECT
)
self.delete_links(sid)
self.delete_nodes(sid)
self.delete_session(sid)
def set_up(self): def set_up(self):
""" """
Query sessions, if there exist any, prompt whether to join one Query sessions, if there exist any, prompt whether to join one
@ -287,31 +283,6 @@ class CoreClient:
response = self.client.edit_node(self.session_id, node_id, position) response = self.client.edit_node(self.session_id, node_id, position)
logging.info("updated node id %s: %s", node_id, response) logging.info("updated node id %s: %s", node_id, response)
def delete_nodes(self, delete_session=None):
if delete_session is None:
sid = self.session_id
else:
sid = delete_session
for node in self.client.get_session(sid).session.nodes:
response = self.client.delete_node(self.session_id, node.id)
logging.info("delete nodes %s", response)
def delete_links(self, delete_session=None):
if delete_session is None:
sid = self.session_id
else:
sid = delete_session
for link in self.client.get_session(sid).session.links:
response = self.client.delete_link(
self.session_id,
link.node_one_id,
link.node_two_id,
link.interface_one.id,
link.interface_two.id,
)
logging.info("delete links %s", response)
def start_session(self): def start_session(self):
nodes = [x.core_node for x in self.canvas_nodes.values()] nodes = [x.core_node for x in self.canvas_nodes.values()]
links = list(self.links.values()) links = list(self.links.values())
@ -340,18 +311,18 @@ class CoreClient:
service_configs, service_configs,
file_configs, file_configs,
) )
logging.debug("Start session %s, result: %s", self.session_id, response.result) logging.debug("start session(%s), result: %s", self.session_id, response.result)
print(self.servers)
# print(self.client.get_session(self.session_id))
def stop_session(self): def stop_session(self, session_id=None):
response = self.client.stop_session(session_id=self.session_id) if not session_id:
logging.debug("coregrpc.py Stop session, result: %s", response.result) session_id = self.session_id
response = self.client.stop_session(session_id)
logging.debug("stopped session(%s), result: %s", session_id, response.result)
def launch_terminal(self, node_id): def launch_terminal(self, node_id):
response = self.client.get_node_terminal(self.session_id, node_id) response = self.client.get_node_terminal(self.session_id, node_id)
logging.info("get terminal %s", response.terminal) logging.info("get terminal %s", response.terminal)
os.system("xterm -e %s &" % response.terminal) os.system(f"xterm -e {response.terminal} &")
def save_xml(self, file_path): def save_xml(self, file_path):
""" """
@ -361,7 +332,7 @@ class CoreClient:
:return: nothing :return: nothing
""" """
response = self.client.save_xml(self.session_id, file_path) response = self.client.save_xml(self.session_id, file_path)
logging.info("coregrpc.py save xml %s", response) logging.info("saved xml(%s): %s", file_path, response)
self.client.events(self.session_id, self.handle_events) self.client.events(self.session_id, self.handle_events)
def open_xml(self, file_path): def open_xml(self, file_path):
@ -498,38 +469,64 @@ class CoreClient:
) )
return node return node
def delete_wanted_graph_nodes(self, node_ids, edge_tokens): def delete_graph_nodes(self, canvas_nodes):
""" """
remove the nodes selected by the user and anything related to that node remove the nodes selected by the user and anything related to that node
such as link, configurations, interfaces such as link, configurations, interfaces
:param list[int] node_ids: list of nodes to delete :param list canvas_nodes: list of nodes to delete
:param list edge_tokens: list of edges to delete
:return: nothing :return: nothing
""" """
# delete the nodes edges = set()
for i in node_ids: for canvas_node in canvas_nodes:
try: node_id = canvas_node.core_node.id
del self.canvas_nodes[i] if node_id not in self.canvas_nodes:
self.reusable.append(i) logging.error("unknown node: %s", node_id)
if i in self.mobility_configs: continue
del self.mobility_configs[i] del self.canvas_nodes[node_id]
if i in self.wlan_configs: self.reusable.append(node_id)
del self.wlan_configs[i] if node_id in self.mobility_configs:
for key in list(self.emane_model_configs): del self.mobility_configs[node_id]
node_id, _, _ = key if node_id in self.wlan_configs:
if node_id == i: del self.wlan_configs[node_id]
del self.emane_model_configs[key] for key in list(self.emane_model_configs):
except KeyError: node_id, _, _ = key
logging.error("invalid canvas id: %s", i) if node_id == node_id:
self.reusable.sort() del self.emane_model_configs[key]
# delete the edges and interfaces deleted_cidrs = set()
for i in edge_tokens: keep_cidrs = set()
try: for edge in canvas_node.edges:
self.links.pop(i) if edge in edges:
except KeyError: continue
logging.error("invalid edge token: %s", i) edges.add(edge)
if edge.token not in self.links:
logging.error("unknown edge: %s", edge.token)
del self.links[edge.token]
other_id = edge.src
other_interface = edge.src_interface
interface = edge.dst_interface
if canvas_node.id == edge.src:
other_id = edge.dst
other_interface = edge.dst_interface
interface = edge.src_interface
other_node = self.app.canvas.nodes.get(other_id)
if not other_node:
continue
if other_interface:
cidr = self.interfaces_manager.get_cidr(other_interface)
deleted_cidrs.add(cidr)
else:
cidr = self.interfaces_manager.find_subnet(other_node)
if cidr:
keep_cidrs.add(cidr)
else:
cidr = self.interfaces_manager.get_cidr(interface)
deleted_cidrs.add(cidr)
deleted_cidrs = deleted_cidrs - keep_cidrs
for cidr in deleted_cidrs:
self.interfaces_manager.deleted_cidr(cidr)
self.reusable.sort()
def create_interface(self, canvas_node): def create_interface(self, canvas_node):
node = canvas_node.core_node node = canvas_node.core_node

View file

@ -155,6 +155,6 @@ class SessionsDialog(Dialog):
self.join_session(sid) self.join_session(sid)
def shutdown_session(self, sid): def shutdown_session(self, sid):
self.app.core.shutdown_session(sid) self.app.core.stop_session(sid)
self.click_new() self.click_new()
self.destroy() self.destroy()

View file

@ -388,50 +388,8 @@ class CanvasGraph(tk.Canvas):
:param event: :param event:
:return: :return:
""" """
# hide nodes, links, link information that shows on the GUI nodes = self.canvas_management.delete_selected_nodes()
to_delete_nodes, to_delete_edge_tokens = ( self.core.delete_graph_nodes(nodes)
self.canvas_management.delete_selected_nodes()
)
# delete antennas
for cnid in to_delete_nodes:
canvas_node = self.nodes[cnid]
if canvas_node.core_node.type != core_pb2.NodeType.WIRELESS_LAN:
canvas_node.antenna_draw.delete_antennas()
else:
for e in canvas_node.edges:
link_proto = self.core.links[e.token]
node_one_id, node_two_id = (
link_proto.node_one_id,
link_proto.node_two_id,
)
if node_one_id == canvas_node.core_node.id:
neighbor_id = node_two_id
else:
neighbor_id = node_one_id
neighbor = self.core.canvas_nodes[neighbor_id]
if neighbor.core_node.type != core_pb2.NodeType.WIRELESS_LAN:
neighbor.antenna_draw.delete_antenna()
# delete nodes and link info stored in CanvasGraph object
node_ids = []
for nid in to_delete_nodes:
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)
# delete the edge data inside of canvas node
canvas_node_link_to_delete = []
for canvas_id, node in self.nodes.items():
for e in node.edges:
if e.token in to_delete_edge_tokens:
canvas_node_link_to_delete.append(tuple([canvas_id, e]))
for nid, edge in canvas_node_link_to_delete:
self.nodes[nid].edges.remove(edge)
# delete the related data from core
self.core.delete_wanted_graph_nodes(node_ids, to_delete_edge_tokens)
def add_node(self, x, y): def add_node(self, x, y):
plot_id = self.find_all()[0] plot_id = self.find_all()[0]

View file

@ -13,19 +13,38 @@ def random_mac():
class InterfaceManager: class InterfaceManager:
def __init__(self, app, cidr="10.0.0.0/24"): def __init__(self, app, cidr="10.0.0.0/24"):
self.app = app self.app = app
self.default = cidr
self.cidr = IPNetwork(cidr) self.cidr = IPNetwork(cidr)
self.deleted = [] self.deleted = []
self.current = None self.current = None
def reset(self):
self.cidr = IPNetwork(self.default)
self.deleted.clear()
self.current = None
def get_ips(self, node_id): def get_ips(self, node_id):
ip4 = self.current[node_id] ip4 = self.current[node_id]
ip6 = ip4.ipv6() ip6 = ip4.ipv6()
return str(ip4), str(ip6), self.current.prefixlen return str(ip4), str(ip6), self.current.prefixlen
def next_subnet(self): def next_subnet(self):
if self.current: if self.deleted:
self.cidr = self.cidr.next() return self.deleted.pop(0)
return self.cidr else:
if self.current:
self.cidr = self.cidr.next()
return self.cidr
def deleted_cidr(self, cidr):
logging.info("deleted cidr: %s", cidr)
if cidr not in self.deleted:
self.deleted.append(cidr)
self.deleted.sort()
@classmethod
def get_cidr(cls, interface):
return IPNetwork(f"{interface.ip4}/{interface.ip4mask}").cidr
def determine_subnet(self, canvas_src_node, canvas_dst_node): def determine_subnet(self, canvas_src_node, canvas_dst_node):
src_node = canvas_src_node.core_node src_node = canvas_src_node.core_node
@ -40,21 +59,21 @@ class InterfaceManager:
self.current = cidr self.current = cidr
else: else:
self.current = self.next_subnet() self.current = self.next_subnet()
# else:
# self.current = self.cidr
elif not is_src_container and is_dst_container: elif not is_src_container and is_dst_container:
cidr = self.find_subnet(canvas_src_node, visited={dst_node.id}) cidr = self.find_subnet(canvas_src_node, visited={dst_node.id})
if cidr: if cidr:
self.current = self.cidr self.current = cidr
else: else:
self.current = self.next_subnet() self.current = self.next_subnet()
else: else:
logging.info("ignoring subnet change for link between network nodes") logging.info("ignoring subnet change for link between network nodes")
def find_subnet(self, canvas_node, visited): def find_subnet(self, canvas_node, visited=None):
logging.info("finding subnet for node: %s", canvas_node.core_node.name) logging.info("finding subnet for node: %s", canvas_node.core_node.name)
canvas = self.app.canvas canvas = self.app.canvas
cidr = None cidr = None
if not visited:
visited = set()
visited.add(canvas_node.core_node.id) visited.add(canvas_node.core_node.id)
for edge in canvas_node.edges: for edge in canvas_node.edges:
src_node = canvas.nodes[edge.src] src_node = canvas.nodes[edge.src]
@ -68,9 +87,10 @@ class InterfaceManager:
continue continue
visited.add(check_node.core_node.id) visited.add(check_node.core_node.id)
if interface: if interface:
logging.info("found interface: %s", interface) cidr = self.get_cidr(interface)
cidr = IPNetwork(f"{interface.ip4}/{interface.ip4mask}").cidr
break
else: else:
cidr = self.find_subnet(check_node, visited) cidr = self.find_subnet(check_node, visited)
if cidr:
logging.info("found subnet: %s", cidr)
break
return cidr return cidr

View file

@ -1,6 +1,7 @@
""" """
manage deletion manage deletion
""" """
from core.api.grpc import core_pb2
class CanvasComponentManagement: class CanvasComponentManagement:
@ -39,23 +40,51 @@ class CanvasComponentManagement:
self.selected.clear() self.selected.clear()
def delete_selected_nodes(self): def delete_selected_nodes(self):
selected_nodes = list(self.selected.keys())
edges = set() edges = set()
for n in selected_nodes: nodes = []
edges = edges.union(self.canvas.nodes[n].edges) for cnid in self.selected:
edge_canvas_ids = [x.id for x in edges] canvas_node = self.canvas.nodes[cnid]
edge_tokens = [x.token for x in edges] if canvas_node.core_node.type != core_pb2.NodeType.WIRELESS_LAN:
link_infos = [x.link_info.id1 for x in edges] + [x.link_info.id2 for x in edges] canvas_node.antenna_draw.delete_antennas()
else:
for i in edge_canvas_ids: for e in canvas_node.edges:
self.canvas.itemconfig(i, state="hidden") link_proto = self.app.links[e.token]
node_one_id, node_two_id = (
for i in link_infos: link_proto.node_one_id,
self.canvas.itemconfig(i, state="hidden") link_proto.node_two_id,
)
for cnid, bbid in self.selected.items(): if node_one_id == canvas_node.core_node.id:
self.canvas.itemconfig(cnid, state="hidden") neighbor_id = node_two_id
self.canvas.itemconfig(bbid, state="hidden") else:
self.canvas.itemconfig(self.canvas.nodes[cnid].text_id, state="hidden") neighbor_id = node_one_id
neighbor = self.app.canvas_nodes[neighbor_id]
if neighbor.core_node.type != core_pb2.NodeType.WIRELESS_LAN:
neighbor.antenna_draw.delete_antenna()
for node_id in list(self.selected):
bbox_id = self.selected[node_id]
canvas_node = self.canvas.nodes.pop(node_id)
nodes.append(canvas_node)
self.canvas.delete(node_id)
self.canvas.delete(bbox_id)
self.canvas.delete(canvas_node.text_id)
for edge in canvas_node.edges:
if edge in edges:
continue
edges.add(edge)
self.canvas.edges.pop(edge.token)
self.canvas.delete(edge.id)
self.canvas.delete(edge.link_info.id1)
self.canvas.delete(edge.link_info.id2)
other_id = edge.src
other_interface = edge.src_interface
if edge.src == node_id:
other_id = edge.dst
other_interface = edge.dst_interface
other_node = self.canvas.nodes[other_id]
other_node.edges.remove(edge)
try:
other_node.interfaces.remove(other_interface)
except ValueError:
pass
self.selected.clear() self.selected.clear()
return selected_nodes, edge_tokens return nodes