def create_link( self, edge: CanvasEdge, canvas_src_node: CanvasNode, canvas_dst_node: CanvasNode ): """ Create core link for a pair of canvas nodes, with token referencing the canvas edge. """ src_node = canvas_src_node.core_node dst_node = canvas_dst_node.core_node # determine subnet self.interfaces_manager.determine_subnets(canvas_src_node, canvas_dst_node) src_interface = None if NodeUtils.is_container_node(src_node.type): src_interface = self.create_interface(canvas_src_node) edge.src_interface = src_interface self.interface_to_edge[(src_node.id, src_interface.id)] = edge.token dst_interface = None if NodeUtils.is_container_node(dst_node.type): dst_interface = self.create_interface(canvas_dst_node) edge.dst_interface = dst_interface self.interface_to_edge[(dst_node.id, dst_interface.id)] = edge.token link = core_pb2.Link( type=core_pb2.LinkType.WIRED, node_one_id=src_node.id, node_two_id=dst_node.id, interface_one=src_interface, interface_two=dst_interface, ) edge.set_link(link) self.links[edge.token] = edge logging.info("Add link between %s and %s", src_node.name, dst_node.name)
def create_link(self, edge: CanvasEdge, canvas_src_node: CanvasNode, canvas_dst_node: CanvasNode) -> None: """ Create core link for a pair of canvas nodes, with token referencing the canvas edge. """ src_node = canvas_src_node.core_node dst_node = canvas_dst_node.core_node self.ifaces_manager.determine_subnets(canvas_src_node, canvas_dst_node) src_iface = None if NodeUtils.is_container_node(src_node.type): src_iface = self.create_iface(canvas_src_node) self.iface_to_edge[(src_node.id, src_iface.id)] = edge.token edge.src_iface = src_iface canvas_src_node.ifaces[src_iface.id] = src_iface dst_iface = None if NodeUtils.is_container_node(dst_node.type): dst_iface = self.create_iface(canvas_dst_node) self.iface_to_edge[(dst_node.id, dst_iface.id)] = edge.token edge.dst_iface = dst_iface canvas_dst_node.ifaces[dst_iface.id] = dst_iface link = Link( type=LinkType.WIRED, node1_id=src_node.id, node2_id=dst_node.id, iface1=src_iface, iface2=dst_iface, ) edge.set_link(link) self.links[edge.token] = edge logging.info("added link between %s and %s", src_node.name, dst_node.name)
def create_link(self, edge: CanvasEdge, canvas_src_node: CanvasNode, canvas_dst_node: CanvasNode) -> Link: """ Create core link for a pair of canvas nodes, with token referencing the canvas edge. """ src_node = canvas_src_node.core_node dst_node = canvas_dst_node.core_node self.ifaces_manager.determine_subnets(canvas_src_node, canvas_dst_node) src_iface = None if NodeUtils.is_container_node(src_node.type): src_iface = self.create_iface(canvas_src_node) dst_iface = None if NodeUtils.is_container_node(dst_node.type): dst_iface = self.create_iface(canvas_dst_node) link = Link( type=LinkType.WIRED, node1_id=src_node.id, node2_id=dst_node.id, iface1=src_iface, iface2=dst_iface, ) logging.info("added link between %s and %s", src_node.name, dst_node.name) return link
def create_context(self) -> tk.Menu: is_wlan = self.core_node.type == NodeType.WIRELESS_LAN is_emane = self.core_node.type == NodeType.EMANE context = tk.Menu(self.canvas) themes.style_menu(context) if self.app.core.is_runtime(): 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) context.add_command(label="Config 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 ) context.add_command(label="Select Adjacent", state=tk.DISABLED) context.add_command(label="Hide", state=tk.DISABLED) if NodeUtils.is_container_node(self.core_node.type): context.add_command(label="Shell Window", state=tk.DISABLED) context.add_command(label="Tcpdump", state=tk.DISABLED) context.add_command(label="Tshark", state=tk.DISABLED) context.add_command(label="Wireshark", state=tk.DISABLED) context.add_command(label="View Log", state=tk.DISABLED) else: context.add_command(label="Configure", command=self.show_config) if NodeUtils.is_container_node(self.core_node.type): context.add_command(label="Services", command=self.show_services) context.add_command( label="Config Services", command=self.show_config_services ) if is_emane: context.add_command( label="EMANE Config", command=self.show_emane_config ) if is_wlan: context.add_command(label="WLAN Config", command=self.show_wlan_config) context.add_command( label="Mobility Config", command=self.show_mobility_config ) if NodeUtils.is_wireless_node(self.core_node.type): context.add_command( label="Link To Selected", command=self.wireless_link_selected ) context.add_command(label="Select Members", state=tk.DISABLED) context.add_command(label="Select Adjacent", state=tk.DISABLED) context.add_command(label="Create Link To", state=tk.DISABLED) context.add_command(label="Assign To", state=tk.DISABLED) context.add_command(label="Move To", state=tk.DISABLED) context.add_command(label="Cut", state=tk.DISABLED) context.add_command(label="Copy", state=tk.DISABLED) context.add_command(label="Paste", state=tk.DISABLED) context.add_command(label="Delete", state=tk.DISABLED) context.add_command(label="Hide", state=tk.DISABLED) return context
def save_edge(self, edge: CanvasEdge, canvas_src_node: CanvasNode, canvas_dst_node: CanvasNode) -> None: self.links[edge.token] = edge src_node = canvas_src_node.core_node dst_node = canvas_dst_node.core_node if NodeUtils.is_container_node(src_node.type): src_iface_id = edge.link.iface1.id self.iface_to_edge[(src_node.id, src_iface_id)] = edge if NodeUtils.is_container_node(dst_node.type): dst_iface_id = edge.link.iface2.id self.iface_to_edge[(dst_node.id, dst_iface_id)] = edge
def store_nodes(self) -> None: """ store all CORE nodes (nodes that execute commands) from all existing nodes """ for nid, node in self.app.core.canvas_nodes.items(): if NodeUtils.is_container_node(node.core_node.type): self.executable_nodes[node.core_node.name] = nid
def click_apply(self) -> None: error = False # update core node self.node.name = self.name.get() if NodeUtils.is_image_node(self.node.type): self.node.image = self.container_image.get() server = self.server.get() if NodeUtils.is_container_node(self.node.type): if server == DEFAULT_SERVER: self.node.server = None else: 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 # update node interface data for iface in self.canvas_node.ifaces.values(): data = self.ifaces[iface.id] error = not data.validate(self, iface) if error: break # redraw if not error: self.canvas_node.redraw() self.destroy()
def show_context(self, event: tk.Event) -> None: # clear existing menu self.context.delete(0, tk.END) is_wlan = self.core_node.type == NodeType.WIRELESS_LAN is_emane = self.core_node.type == NodeType.EMANE if self.app.core.is_runtime(): self.context.add_command(label="Configure", command=self.show_config) if is_emane: self.context.add_command( label="EMANE Config", command=self.show_emane_config ) if is_wlan: self.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: self.context.add_command( label="Mobility Player", command=self.show_mobility_player ) else: self.context.add_command(label="Configure", command=self.show_config) if NodeUtils.is_container_node(self.core_node.type): self.context.add_command(label="Services", command=self.show_services) self.context.add_command( label="Config Services", command=self.show_config_services ) if is_emane: self.context.add_command( label="EMANE Config", command=self.show_emane_config ) if is_wlan: self.context.add_command( label="WLAN Config", command=self.show_wlan_config ) self.context.add_command( label="Mobility Config", command=self.show_mobility_config ) if NodeUtils.is_wireless_node(self.core_node.type): self.context.add_command( label="Link To Selected", command=self.wireless_link_selected ) unlink_menu = tk.Menu(self.context) for edge in self.edges: other_id = edge.src if self.id == other_id: other_id = edge.dst other_node = self.canvas.nodes[other_id] func_unlink = functools.partial(self.click_unlink, edge) unlink_menu.add_command( label=other_node.core_node.name, command=func_unlink ) themes.style_menu(unlink_menu) self.context.add_cascade(label="Unlink", menu=unlink_menu) edit_menu = tk.Menu(self.context) themes.style_menu(edit_menu) edit_menu.add_command(label="Cut", command=self.click_cut) edit_menu.add_command(label="Copy", command=self.canvas_copy) edit_menu.add_command(label="Delete", command=self.canvas_delete) self.context.add_cascade(label="Edit", menu=edit_menu) self.context.tk_popup(event.x_root, event.y_root)
def store_nodes(self) -> None: """ store all CORE nodes (nodes that execute commands) from all existing nodes """ for node in self.app.core.session.nodes.values(): if NodeUtils.is_container_node(node.type): self.executable_nodes[node.name] = node.id
def create_link( self, edge: CanvasEdge, canvas_src_node: CanvasNode, canvas_dst_node: CanvasNode ) -> None: """ Create core link for a pair of canvas nodes, with token referencing the canvas edge. """ src_node = canvas_src_node.core_node dst_node = canvas_dst_node.core_node # determine subnet self.ifaces_manager.determine_subnets(canvas_src_node, canvas_dst_node) src_iface = None if NodeUtils.is_container_node(src_node.type): src_iface = self.create_iface(canvas_src_node) self.iface_to_edge[(src_node.id, src_iface.id)] = edge.token dst_iface = None if NodeUtils.is_container_node(dst_node.type): dst_iface = self.create_iface(canvas_dst_node) self.iface_to_edge[(dst_node.id, dst_iface.id)] = edge.token link = Link( type=LinkType.WIRED, node1_id=src_node.id, node2_id=dst_node.id, iface1=src_iface, iface2=dst_iface, ) # assign after creating link proto, since interfaces are copied if src_iface: iface1 = link.iface1 edge.src_iface = iface1 canvas_src_node.ifaces[iface1.id] = iface1 if dst_iface: iface2 = link.iface2 edge.dst_iface = iface2 canvas_dst_node.ifaces[iface2.id] = iface2 edge.set_link(link) self.links[edge.token] = edge logging.info("Add link between %s and %s", src_node.name, dst_node.name)
def create_link(self, edge, canvas_src_node, canvas_dst_node): """ Create core link for a pair of canvas nodes, with token referencing the canvas edge. :param edge: edge for link :param canvas_src_node: canvas node one :param canvas_dst_node: canvas node two :return: nothing """ src_node = canvas_src_node.core_node dst_node = canvas_dst_node.core_node # determine subnet self.interfaces_manager.determine_subnet(canvas_src_node, canvas_dst_node) src_interface = None if NodeUtils.is_container_node(src_node.type): src_interface = self.create_interface(canvas_src_node) edge.src_interface = src_interface self.interface_to_edge[(src_node.id, src_interface.id)] = edge.token dst_interface = None if NodeUtils.is_container_node(dst_node.type): dst_interface = self.create_interface(canvas_dst_node) edge.dst_interface = dst_interface self.interface_to_edge[(dst_node.id, dst_interface.id)] = edge.token link = core_pb2.Link( type=core_pb2.LinkType.WIRED, node_one_id=src_node.id, node_two_id=dst_node.id, interface_one=src_interface, interface_two=dst_interface, ) edge.set_link(link) self.links[edge.token] = edge
def on_enter(self, event: tk.Event) -> None: is_runtime = self.app.core.is_runtime() has_observer = self.app.core.observer is not None is_container = NodeUtils.is_container_node(self.core_node.type) if is_runtime and has_observer and is_container: self.tooltip.text.set("waiting...") self.tooltip.on_enter(event) try: output = self.app.core.run(self.core_node.id) self.tooltip.text.set(output) except grpc.RpcError as e: self.app.show_grpc_exception("Observer Error", e)
def determine_subnet(self, canvas_src_node, canvas_dst_node): src_node = canvas_src_node.core_node dst_node = canvas_dst_node.core_node is_src_container = NodeUtils.is_container_node(src_node.type) is_dst_container = NodeUtils.is_container_node(dst_node.type) if is_src_container and is_dst_container: self.current_subnet = self.next_subnet() elif is_src_container and not is_dst_container: subnet = self.find_subnet(canvas_dst_node, visited={src_node.id}) if subnet: self.current_subnet = subnet else: self.current_subnet = self.next_subnet() elif not is_src_container and is_dst_container: subnet = self.find_subnet(canvas_src_node, visited={dst_node.id}) if subnet: self.current_subnet = subnet else: self.current_subnet = self.next_subnet() else: logging.info( "ignoring subnet change for link between network nodes")
def draw(self) -> None: self.columnconfigure(0, weight=1) node = self.canvas_node.core_node frame = DetailsFrame(self) frame.grid(sticky=tk.EW) frame.add_detail("ID", node.id) frame.add_detail("Name", node.name) if NodeUtils.is_model_node(node.type): frame.add_detail("Type", node.model) if NodeUtils.is_container_node(node.type): for index, service in enumerate(sorted(node.services)): if index == 0: frame.add_detail("Services", service) else: frame.add_detail("", service) if node.type == NodeType.EMANE: emane = node.emane.split("_")[1:] frame.add_detail("EMANE", emane) if NodeUtils.is_image_node(node.type): frame.add_detail("Image", node.image) if NodeUtils.is_container_node(node.type): server = node.server if node.server else "localhost" frame.add_detail("Server", server)
def get_service_file_configs_proto( self) -> List[services_pb2.ServiceFileConfig]: configs = [] for node in self.session.nodes.values(): if not NodeUtils.is_container_node(node.type): continue if not node.service_file_configs: continue for service, file_configs in node.service_file_configs.items(): for file, data in file_configs.items(): config_proto = services_pb2.ServiceFileConfig( node_id=node.id, service=service, file=file, data=data) configs.append(config_proto) return configs
def get_service_file_configs_proto(self) -> List[ServiceFileConfig]: configs = [] for canvas_node in self.canvas_nodes.values(): if not NodeUtils.is_container_node(canvas_node.core_node.type): continue if not canvas_node.service_file_configs: continue node_id = canvas_node.core_node.id for service, file_configs in canvas_node.service_file_configs.items(): for file, data in file_configs.items(): config_proto = ServiceFileConfig( node_id=node_id, service=service, file=file, data=data ) configs.append(config_proto) return configs
def get_config_service_configs_proto( self) -> List[configservices_pb2.ConfigServiceConfig]: config_service_protos = [] for node in self.session.nodes.values(): if not NodeUtils.is_container_node(node.type): continue if not node.config_service_configs: continue for name, service_config in node.config_service_configs.items(): config_proto = configservices_pb2.ConfigServiceConfig( node_id=node.id, name=name, templates=service_config.templates, config=service_config.config, ) config_service_protos.append(config_proto) return config_service_protos
def get_config_service_configs_proto(self) -> List[ConfigServiceConfig]: config_service_protos = [] for canvas_node in self.canvas_nodes.values(): if not NodeUtils.is_container_node(canvas_node.core_node.type): continue if not canvas_node.config_service_configs: continue node_id = canvas_node.core_node.id for name, service_config in canvas_node.config_service_configs.items(): config = service_config.get("config", {}) config_proto = ConfigServiceConfig( node_id=node_id, name=name, templates=service_config["templates"], config=config, ) config_service_protos.append(config_proto) return config_service_protos
def get_service_configs_proto(self) -> List[services_pb2.ServiceConfig]: configs = [] for node in self.session.nodes.values(): if not NodeUtils.is_container_node(node.type): continue if not node.service_configs: continue for name, config in node.service_configs.items(): config_proto = services_pb2.ServiceConfig( node_id=node.id, service=name, directories=config.dirs, files=config.configs, startup=config.startup, validate=config.validate, shutdown=config.shutdown, ) configs.append(config_proto) return configs
def get_service_configs_proto(self) -> List[ServiceConfig]: configs = [] for canvas_node in self.canvas_nodes.values(): if not NodeUtils.is_container_node(canvas_node.core_node.type): continue if not canvas_node.service_configs: continue node_id = canvas_node.core_node.id for name, config in canvas_node.service_configs.items(): config_proto = ServiceConfig( node_id=node_id, service=name, directories=config.dirs, files=config.configs, startup=config.startup, validate=config.validate, shutdown=config.shutdown, ) configs.append(config_proto) return configs
def config_apply(self): # update core node self.node.name = self.name.get() if NodeUtils.is_image_node(self.node.type): self.node.image = self.container_image.get() server = self.server.get() 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 # redraw self.canvas_node.redraw() self.destroy()
def double_click(self, event: tk.Event) -> None: if self.app.core.is_runtime(): if NodeUtils.is_container_node(self.core_node.type): self.canvas.core.launch_terminal(self.core_node.id) else: self.show_config()
def click_apply(self) -> None: error = False # update core node self.node.name = self.name.get() if NodeUtils.is_image_node(self.node.type): self.node.image = self.container_image.get() server = self.server.get() 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 # update node interface data for iface in self.canvas_node.ifaces.values(): data = self.ifaces[iface.id] # validate ip4 ip4_net = data.ip4.get() if not check_ip4(self, iface.name, ip4_net): error = True break if ip4_net: ip4, ip4_mask = ip4_net.split("/") ip4_mask = int(ip4_mask) else: ip4, ip4_mask = "", 0 iface.ip4 = ip4 iface.ip4_mask = ip4_mask # validate ip6 ip6_net = data.ip6.get() if not check_ip6(self, iface.name, ip6_net): error = True break if ip6_net: ip6, ip6_mask = ip6_net.split("/") ip6_mask = int(ip6_mask) else: ip6, ip6_mask = "", 0 iface.ip6 = ip6 iface.ip6_mask = ip6_mask mac = data.mac.get() auto_mac = data.is_auto.get() if not auto_mac and not netaddr.valid_mac(mac): title = f"MAC Error for {iface.name}" messagebox.showerror(title, "Invalid MAC Address") error = True break elif not auto_mac: mac = netaddr.EUI(mac, dialect=netaddr.mac_unix_expanded) iface.mac = str(mac) # redraw if not error: self.canvas_node.redraw() self.destroy()
def draw(self) -> None: self.top.columnconfigure(0, weight=1) row = 0 # field states state = tk.DISABLED if self.app.core.is_runtime() else tk.NORMAL combo_state = tk.DISABLED if self.app.core.is_runtime() else "readonly" # field frame frame = ttk.Frame(self.top) frame.grid(sticky=tk.EW) frame.columnconfigure(1, weight=1) # icon field label = ttk.Label(frame, text="Icon") label.grid(row=row, column=0, sticky=tk.EW, padx=PADX, pady=PADY) self.image_button = ttk.Button( frame, text="Icon", image=self.image, compound=tk.NONE, command=self.click_icon, ) self.image_button.grid(row=row, column=1, sticky=tk.EW) row += 1 # name field label = ttk.Label(frame, text="Name") label.grid(row=row, column=0, sticky=tk.EW, padx=PADX, pady=PADY) entry = validation.NodeNameEntry(frame, textvariable=self.name, state=state) entry.grid(row=row, column=1, sticky=tk.EW) row += 1 # node type field if NodeUtils.is_model_node(self.node.type): label = ttk.Label(frame, text="Type") label.grid(row=row, column=0, sticky=tk.EW, padx=PADX, pady=PADY) combobox = ttk.Combobox( frame, textvariable=self.type, values=list(NodeUtils.NODE_MODELS), state=combo_state, ) combobox.grid(row=row, column=1, sticky=tk.EW) row += 1 # container image field if NodeUtils.is_image_node(self.node.type): label = ttk.Label(frame, text="Image") label.grid(row=row, column=0, sticky=tk.EW, padx=PADX, pady=PADY) entry = ttk.Entry(frame, textvariable=self.container_image, state=state) entry.grid(row=row, column=1, sticky=tk.EW) row += 1 if NodeUtils.is_container_node(self.node.type): # server frame.grid(sticky=tk.EW) frame.columnconfigure(1, weight=1) label = ttk.Label(frame, text="Server") label.grid(row=row, column=0, sticky=tk.EW, padx=PADX, pady=PADY) servers = ["localhost"] servers.extend(list(sorted(self.app.core.servers.keys()))) combobox = ttk.Combobox(frame, textvariable=self.server, values=servers, state=combo_state) combobox.grid(row=row, column=1, sticky=tk.EW) row += 1 if NodeUtils.is_rj45_node(self.node.type): response = self.app.core.client.get_ifaces() logging.debug("host machine available interfaces: %s", response) ifaces = ListboxScroll(frame) ifaces.listbox.config(state=state) ifaces.grid(row=row, column=0, columnspan=2, sticky=tk.EW, padx=PADX, pady=PADY) for inf in sorted(response.ifaces[:]): ifaces.listbox.insert(tk.END, inf) row += 1 ifaces.listbox.bind("<<ListboxSelect>>", self.iface_select) # interfaces if self.canvas_node.ifaces: self.draw_ifaces() self.draw_spacer() self.draw_buttons()
def draw(self): self.top.columnconfigure(0, weight=1) row = 0 # field frame frame = ttk.Frame(self.top) frame.grid(sticky="ew") frame.columnconfigure(1, weight=1) # icon field label = ttk.Label(frame, text="Icon") label.grid(row=row, column=0, sticky="ew", padx=PADX, pady=PADY) self.image_button = ttk.Button( frame, text="Icon", image=self.image, compound=tk.NONE, command=self.click_icon, ) self.image_button.grid(row=row, column=1, sticky="ew") row += 1 # name field label = ttk.Label(frame, text="Name") label.grid(row=row, column=0, sticky="ew", padx=PADX, pady=PADY) entry = ttk.Entry( frame, textvariable=self.name, validate="key", validatecommand=(self.app.validation.name, "%P"), ) entry.bind( "<FocusOut>", lambda event: self.app.validation.focus_out(event, "noname")) entry.grid(row=row, column=1, sticky="ew") row += 1 # node type field if NodeUtils.is_model_node(self.node.type): label = ttk.Label(frame, text="Type") label.grid(row=row, column=0, sticky="ew", padx=PADX, pady=PADY) combobox = ttk.Combobox( frame, textvariable=self.type, values=list(NodeUtils.NODE_MODELS), state="readonly", ) combobox.grid(row=row, column=1, sticky="ew") row += 1 # container image field if NodeUtils.is_image_node(self.node.type): label = ttk.Label(frame, text="Image") label.grid(row=row, column=0, sticky="ew", padx=PADX, pady=PADY) entry = ttk.Entry(frame, textvariable=self.container_image) entry.grid(row=row, column=1, sticky="ew") row += 1 if NodeUtils.is_container_node(self.node.type): # server frame.grid(sticky="ew") frame.columnconfigure(1, weight=1) label = ttk.Label(frame, text="Server") label.grid(row=row, column=0, sticky="ew", padx=PADX, pady=PADY) servers = ["localhost"] servers.extend(list(sorted(self.app.core.servers.keys()))) combobox = ttk.Combobox(frame, textvariable=self.server, values=servers, state="readonly") combobox.grid(row=row, column=1, sticky="ew") row += 1 if NodeUtils.is_rj45_node(self.node.type): response = self.app.core.client.get_interfaces() logging.debug("host machine available interfaces: %s", response) interfaces = ListboxScroll(frame) interfaces.grid(row=row, column=0, columnspan=2, sticky="ew", padx=PADX, pady=PADY) for inf in sorted(response.interfaces[:]): interfaces.listbox.insert(tk.END, inf) row += 1 interfaces.listbox.bind("<<ListboxSelect>>", self.interface_select) # interfaces if self.canvas_node.interfaces: self.draw_interfaces() self.draw_spacer() self.draw_buttons()