Merge branch 'coretk' into coretk-config

This commit is contained in:
Huy Pham 2019-11-06 14:37:19 -08:00
commit a0039d3991
14 changed files with 463 additions and 96 deletions

View file

@ -15,7 +15,11 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install pipenv
cd coretk
cd daemon
cp setup.py.in setup.py
cp core/constants.py.in core/constants.py
sed -i 's/True/False/g' core/constants.py
cd ../coretk
pipenv install --dev
- name: isort
run: |

View file

@ -42,15 +42,15 @@ def check_directory():
for background in LOCAL_BACKGROUND_PATH.glob("*"):
new_background = BACKGROUNDS_PATH.joinpath(background.name)
shutil.copy(background, new_background)
with CONFIG_PATH.open("w") as f:
yaml.dump(
{"servers": [{"name": "example", "address": "127.0.0.1", "port": 50051}]},
f,
Dumper=IndentDumper,
default_flow_style=False,
)
config = {"servers": [{"name": "example", "address": "127.0.0.1", "port": 50051}]}
save_config(config)
def read_config():
with CONFIG_PATH.open("r") as f:
return yaml.load(f, Loader=yaml.SafeLoader)
def save_config(config):
with CONFIG_PATH.open("w") as f:
yaml.dump(config, f, Dumper=IndentDumper, default_flow_style=False)

View file

@ -75,6 +75,7 @@ class CoreClient:
self.app = app
self.master = app.master
self.interface_helper = None
self.services = {}
# distributed server data
self.servers = {}
@ -228,9 +229,16 @@ class CoreClient:
:return: existing sessions
"""
self.client.connect()
response = self.client.get_sessions()
# get service information
response = self.client.get_services()
for service in response.services:
group_services = self.services.setdefault(service.group, [])
group_services.append(service)
# if there are no sessions, create a new session, else join a session
response = self.client.get_sessions()
logging.info("current sessions: %s", response)
sessions = response.sessions
if len(sessions) == 0:
self.create_new_session()

View file

@ -543,7 +543,9 @@ class CoreMenubar(object):
observer_widget_menu.add_command(
label="PIM neighbors", command=action.sub_menu_items
)
observer_widget_menu.add_command(label="Edit...", command=action.sub_menu_items)
observer_widget_menu.add_command(
label="Edit...", command=self.menu_action.edit_observer_widgets
)
widget_menu.add_cascade(label="Observer Widgets", menu=observer_widget_menu)

View file

@ -1,8 +1,8 @@
import logging
import tkinter as tk
# from core.api.grpc import core_pb2
from coretk.coretoolbarhelp import CoreToolbarHelp
from coretk.dialogs.customnodes import CustomNodesDialog
from coretk.graph import GraphMode
from coretk.images import ImageEnum, Images
from coretk.tooltip import CreateToolTip
@ -233,11 +233,12 @@ class CoreToolbar(object):
self.canvas.draw_node_image = Images.get(ImageEnum.OVS)
self.canvas.draw_node_name = "OVS"
# TODO what graph node is this
def pick_editnode(self, main_button):
self.network_layer_option_menu.destroy()
main_button.configure(image=Images.get(ImageEnum.EDITNODE))
logging.debug("Pick editnode option")
dialog = CustomNodesDialog(self.app, self.app)
dialog.show()
def draw_network_layer_options(self, network_layer_button):
"""

View file

@ -0,0 +1,158 @@
import tkinter as tk
from coretk.dialogs.dialog import Dialog
from coretk.dialogs.nodeicon import IconDialog
from coretk.widgets import CheckboxList, ListboxScroll
class ServicesSelectDialog(Dialog):
def __init__(self, master, app):
super().__init__(master, app, "Node Services", modal=True)
self.groups = None
self.services = None
self.current = None
self.current_services = set()
self.draw()
def draw(self):
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
frame = tk.Frame(self)
frame.grid(stick="nsew")
frame.rowconfigure(0, weight=1)
for i in range(3):
frame.columnconfigure(i, weight=1)
self.groups = ListboxScroll(frame, text="Groups")
self.groups.grid(row=0, column=0, sticky="nsew")
for group in sorted(self.app.core.services):
self.groups.listbox.insert(tk.END, group)
self.groups.listbox.bind("<<ListboxSelect>>", self.handle_group_change)
self.services = CheckboxList(
frame, text="Services", clicked=self.service_clicked
)
self.services.grid(row=0, column=1, sticky="nsew")
self.current = ListboxScroll(frame, text="Selected")
self.current.grid(row=0, column=2, sticky="nsew")
frame = tk.Frame(self)
frame.grid(stick="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Save")
button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
def handle_group_change(self, event):
selection = self.groups.listbox.curselection()
if selection:
index = selection[0]
group = self.groups.listbox.get(index)
self.services.clear()
for service in sorted(self.app.core.services[group], key=lambda x: x.name):
self.services.add(service.name)
def service_clicked(self, name, var):
if var.get() and name not in self.current_services:
self.current_services.add(name)
elif not var.get() and name in self.current_services:
self.current_services.remove(name)
self.current.listbox.delete(0, tk.END)
for name in sorted(self.current_services):
self.current.listbox.insert(tk.END, name)
class CustomNodesDialog(Dialog):
def __init__(self, master, app):
super().__init__(master, app, "Custom Nodes", modal=True)
self.save_button = None
self.delete_button = None
self.name = tk.StringVar()
self.image_button = None
self.image = None
self.draw()
def draw(self):
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.draw_node_config()
self.draw_node_buttons()
self.draw_buttons()
def draw_node_config(self):
frame = tk.Frame(self)
frame.grid(sticky="nsew")
frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1)
scrollbar = tk.Scrollbar(frame, orient=tk.VERTICAL)
scrollbar.grid(row=0, column=1, sticky="ns")
listbox = tk.Listbox(frame, selectmode=tk.SINGLE, yscrollcommand=scrollbar.set)
listbox.grid(row=0, column=0, sticky="nsew")
scrollbar.config(command=listbox.yview)
frame = tk.Frame(frame)
frame.grid(row=0, column=2, sticky="nsew")
frame.columnconfigure(0, weight=1)
entry = tk.Entry(frame, textvariable=self.name)
entry.grid(sticky="ew")
self.image_button = tk.Button(frame, text="Icon", command=self.click_icon)
self.image_button.grid(sticky="ew")
button = tk.Button(frame, text="Services", command=self.click_services)
button.grid(sticky="ew")
def draw_node_buttons(self):
frame = tk.Frame(self)
frame.grid(pady=2, sticky="ew")
for i in range(3):
frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Create", command=self.click_create)
button.grid(row=0, column=0, sticky="ew")
self.save_button = tk.Button(
frame, text="Save", state=tk.DISABLED, command=self.click_save
)
self.save_button.grid(row=0, column=1, sticky="ew")
self.delete_button = tk.Button(
frame, text="Delete", state=tk.DISABLED, command=self.click_delete
)
self.delete_button.grid(row=0, column=2, sticky="ew")
def draw_buttons(self):
frame = tk.Frame(self)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Save", command=self.click_save)
button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
def click_icon(self):
dialog = IconDialog(self, self.app, self.name.get(), self.image)
dialog.show()
if dialog.image:
self.image = dialog.image
self.image_button.config(image=self.image)
def click_services(self):
dialog = ServicesSelectDialog(self, self.app)
dialog.show()
def click_create(self):
pass
def click_save(self):
pass
def click_delete(self):
pass

View file

@ -2,7 +2,7 @@ import tkinter as tk
from tkinter import ttk
from coretk.dialogs.dialog import Dialog
from coretk.dialogs.nodeicon import NodeIconDialog
from coretk.dialogs.nodeicon import IconDialog
from coretk.dialogs.nodeservice import NodeServicesDialog
NETWORKNODETYPES = ["switch", "hub", "wlan", "rj45", "tunnel"]
@ -91,7 +91,9 @@ class NodeConfigDialog(Dialog):
dialog.show()
def click_icon(self):
dialog = NodeIconDialog(self, self.app, self.canvas_node)
dialog = IconDialog(
self, self.app, self.canvas_node.name, self.canvas_node.image
)
dialog.show()
if dialog.image:
self.image = dialog.image

View file

@ -6,18 +6,12 @@ from coretk.dialogs.dialog import Dialog
from coretk.images import Images
class NodeIconDialog(Dialog):
def __init__(self, master, app, canvas_node):
"""
create an instance of ImageModification
:param master: dialog master
:param coretk.app.Application: main app
:param coretk.graph.CanvasNode canvas_node: node object
"""
super().__init__(master, app, f"{canvas_node.name} Icon", modal=True)
class IconDialog(Dialog):
def __init__(self, master, app, name, image):
super().__init__(master, app, f"{name} Icon", modal=True)
self.file_path = tk.StringVar()
self.image_label = None
self.image = canvas_node.image
self.image = image
self.draw()
def draw(self):

View file

@ -6,58 +6,6 @@ from tkinter import messagebox
from coretk.dialogs.dialog import Dialog
CORE_DEFAULT_GROUPS = ["EMANE", "FRR", "ProtoSvc", "Quagga", "Security", "Utility"]
DEFAULT_GROUP_RADIO_VALUE = {
"EMANE": 1,
"FRR": 2,
"ProtoSvc": 3,
"Quagga": 4,
"Security": 5,
"Utility": 6,
}
DEFAULT_GROUP_SERVICES = {
"EMANE": ["transportd"],
"FRR": [
"FRRBable",
"FRRBGP",
"FRROSPFv2",
"FRROSPFv3",
"FRRpimd",
"FRRRIP",
"FRRRIPNG",
"FRRzebra",
],
"ProtoSvc": ["MGEN_Sink", "MgenActor", "SMF"],
"Quagga": [
"Babel",
"BGP",
"OSPFv2",
"OSPFv3",
"OSPFv3MDR",
"RIP",
"RIPNG",
"Xpimd",
"zebra",
],
"Security": ["Firewall", "IPsec", "NAT", "VPNClient", "VPNServer"],
"Utility": [
"atd",
"DefaultMulticastRoute",
"DefaultRoute",
"DHCP",
"DHCPClient",
"FTP",
"HTTP",
"IPForward ",
"pcap",
"radvd",
"SSH",
"StaticRoute",
"ucarp",
"UserDefined",
],
}
class NodeServicesDialog(Dialog):
def __init__(self, master, app, canvas_node):
@ -66,6 +14,7 @@ class NodeServicesDialog(Dialog):
self.core_groups = []
self.service_to_config = None
self.config_frame = None
self.services_list = None
self.draw()
def draw(self):
@ -110,7 +59,7 @@ class NodeServicesDialog(Dialog):
listbox.grid(row=1, column=0, sticky="nsew")
listbox.bind("<<ListboxSelect>>", self.handle_group_change)
for group in CORE_DEFAULT_GROUPS:
for group in sorted(self.app.core.services):
listbox.insert(tk.END, group)
scrollbar.config(command=listbox.yview)
@ -127,7 +76,7 @@ class NodeServicesDialog(Dialog):
scrollbar = tk.Scrollbar(frame, orient=tk.VERTICAL)
scrollbar.grid(row=1, column=1, sticky="ns")
listbox = tk.Listbox(
self.services_list = tk.Listbox(
frame,
selectmode=tk.SINGLE,
yscrollcommand=scrollbar.set,
@ -135,10 +84,10 @@ class NodeServicesDialog(Dialog):
highlightthickness=0.5,
bd=0,
)
listbox.grid(row=1, column=0, sticky="nsew")
listbox.bind("<<ListboxSelect>>", self.handle_service_change)
self.services_list.grid(row=1, column=0, sticky="nsew")
self.services_list.bind("<<ListboxSelect>>", self.handle_service_change)
scrollbar.config(command=listbox.yview)
scrollbar.config(command=self.services_list.yview)
def draw_current_services(self):
frame = tk.Frame(self.config_frame)
@ -188,11 +137,9 @@ class NodeServicesDialog(Dialog):
self.display_group_services(s)
def display_group_services(self, group_name):
group_services_frame = self.config_frame.grid_slaves(row=0, column=1)[0]
listbox = group_services_frame.grid_slaves(row=1, column=0)[0]
listbox.delete(0, tk.END)
for s in DEFAULT_GROUP_SERVICES[group_name]:
listbox.insert(tk.END, s)
self.services_list.delete(0, tk.END)
for service in sorted(self.app.core.services[group_name], key=lambda x: x.name):
self.services_list.insert(tk.END, service.name)
def handle_service_change(self, event):
print("select group service")

View file

@ -0,0 +1,148 @@
import tkinter as tk
from coretk.dialogs.dialog import Dialog
class Widget:
def __init__(self, name, command):
self.name = name
self.command = command
class ObserverWidgetsDialog(Dialog):
def __init__(self, master, app):
super().__init__(master, app, "Observer Widgets", modal=True)
self.config_widgets = {}
self.widgets = None
self.save_button = None
self.delete_button = None
self.selected = None
self.selected_index = None
self.name = tk.StringVar()
self.command = tk.StringVar()
self.draw()
def draw(self):
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.draw_widgets()
self.draw_widget_fields()
self.draw_widget_buttons()
self.draw_apply_buttons()
def draw_widgets(self):
frame = tk.Frame(self)
frame.grid(sticky="nsew")
frame.columnconfigure(0, weight=1)
frame.rowconfigure(0, weight=1)
scrollbar = tk.Scrollbar(frame, orient=tk.VERTICAL)
scrollbar.grid(row=0, column=1, sticky="ns")
self.widgets = tk.Listbox(
frame, selectmode=tk.SINGLE, yscrollcommand=scrollbar.set
)
self.widgets.grid(row=0, column=0, sticky="nsew")
self.widgets.bind("<<ListboxSelect>>", self.handle_widget_change)
scrollbar.config(command=self.widgets.yview)
def draw_widget_fields(self):
frame = tk.Frame(self)
frame.grid(sticky="ew")
frame.columnconfigure(1, weight=1)
label = tk.Label(frame, text="Name")
label.grid(row=0, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.name)
entry.grid(row=0, column=1, sticky="ew")
label = tk.Label(frame, text="Command")
label.grid(row=1, column=0, sticky="w")
entry = tk.Entry(frame, textvariable=self.command)
entry.grid(row=1, column=1, sticky="ew")
def draw_widget_buttons(self):
frame = tk.Frame(self)
frame.grid(pady=2, sticky="ew")
for i in range(3):
frame.columnconfigure(i, weight=1)
button = tk.Button(frame, text="Create", command=self.click_create)
button.grid(row=0, column=0, sticky="ew")
self.save_button = tk.Button(
frame, text="Save", state=tk.DISABLED, command=self.click_save
)
self.save_button.grid(row=0, column=1, sticky="ew")
self.delete_button = tk.Button(
frame, text="Delete", state=tk.DISABLED, command=self.click_delete
)
self.delete_button.grid(row=0, column=2, sticky="ew")
def draw_apply_buttons(self):
frame = tk.Frame(self)
frame.grid(sticky="ew")
for i in range(2):
frame.columnconfigure(i, weight=1)
button = tk.Button(
frame, text="Save Configuration", command=self.click_save_configuration
)
button.grid(row=0, column=0, sticky="ew")
button = tk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
def click_save_configuration(self):
pass
def click_create(self):
name = self.name.get()
if name not in self.config_widgets:
command = self.command.get()
widget = Widget(name, command)
self.config_widgets[name] = widget
self.widgets.insert(tk.END, name)
def click_save(self):
name = self.name.get()
if self.selected:
previous_name = self.selected
self.selected = name
widget = self.config_widgets.pop(previous_name)
widget.name = name
widget.command = self.command.get()
self.config_widgets[name] = widget
self.widgets.delete(self.selected_index)
self.widgets.insert(self.selected_index, name)
self.widgets.selection_set(self.selected_index)
def click_delete(self):
if self.selected:
self.widgets.delete(self.selected_index)
del self.config_widgets[self.selected]
self.selected = None
self.selected_index = None
self.name.set("")
self.command.set("")
self.widgets.selection_clear(0, tk.END)
self.save_button.config(state=tk.DISABLED)
self.delete_button.config(state=tk.DISABLED)
def handle_widget_change(self, event):
selection = self.widgets.curselection()
if selection:
self.selected_index = selection[0]
self.selected = self.widgets.get(self.selected_index)
widget = self.config_widgets[self.selected]
self.name.set(widget.name)
self.command.set(widget.command)
self.save_button.config(state=tk.NORMAL)
self.delete_button.config(state=tk.NORMAL)
else:
self.selected_index = None
self.selected = None
self.save_button.config(state=tk.DISABLED)
self.delete_button.config(state=tk.DISABLED)

View file

@ -1,5 +1,6 @@
import tkinter as tk
from coretk import appdirs
from coretk.coreclient import CoreServer
from coretk.dialogs.dialog import Dialog
@ -39,12 +40,7 @@ class ServersDialog(Dialog):
scrollbar.grid(row=0, column=1, sticky="ns")
self.servers = tk.Listbox(
frame,
selectmode=tk.SINGLE,
yscrollcommand=scrollbar.set,
relief=tk.FLAT,
highlightthickness=0.5,
bd=0,
frame, selectmode=tk.SINGLE, yscrollcommand=scrollbar.set
)
self.servers.grid(row=0, column=0, sticky="nsew")
self.servers.bind("<<ListboxSelect>>", self.handle_server_change)
@ -113,7 +109,14 @@ class ServersDialog(Dialog):
button.grid(row=0, column=1, sticky="ew")
def click_save_configuration(self):
pass
servers = []
for name in sorted(self.app.core.servers):
server = self.app.core.servers[name]
servers.append(
{"name": server.name, "address": server.address, "port": server.port}
)
self.app.config["servers"] = servers
appdirs.save_config(self.app.config)
def click_create(self):
name = self.name.get()
@ -126,7 +129,7 @@ class ServersDialog(Dialog):
def click_save(self):
name = self.name.get()
if self.selected and name not in self.app.core.servers:
if self.selected:
previous_name = self.selected
self.selected = name
server = self.app.core.servers.pop(previous_name)

View file

@ -5,7 +5,7 @@ wlan configuration
import tkinter as tk
from coretk.dialogs.dialog import Dialog
from coretk.dialogs.nodeicon import NodeIconDialog
from coretk.dialogs.nodeicon import IconDialog
class WlanConfigDialog(Dialog):
@ -167,7 +167,9 @@ class WlanConfigDialog(Dialog):
button.grid(row=0, column=1, padx=2, sticky="ew")
def click_icon(self):
dialog = NodeIconDialog(self, self.app, self.canvas_node)
dialog = IconDialog(
self, self.app, self.canvas_node.name, self.canvas_node.image
)
dialog.show()
if dialog.image:
self.image = dialog.image

View file

@ -11,6 +11,7 @@ from coretk.appdirs import XML_PATH
from coretk.dialogs.canvasbackground import CanvasBackgroundDialog
from coretk.dialogs.canvassizeandscale import SizeAndScaleDialog
from coretk.dialogs.hooks import HooksDialog
from coretk.dialogs.observerwidgets import ObserverWidgetsDialog
from coretk.dialogs.servers import ServersDialog
from coretk.dialogs.sessionoptions import SessionOptionsDialog
from coretk.dialogs.sessions import SessionsDialog
@ -403,3 +404,7 @@ class MenuAction:
logging.debug("Click session emulation servers")
dialog = ServersDialog(self.app, self.app)
dialog.show()
def edit_observer_widgets(self):
dialog = ObserverWidgetsDialog(self.app, self.app)
dialog.show()

93
coretk/coretk/widgets.py Normal file
View file

@ -0,0 +1,93 @@
import tkinter as tk
from functools import partial
class FrameScroll(tk.LabelFrame):
def __init__(self, master=None, cnf={}, **kw):
super().__init__(master, cnf, **kw)
self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1)
self.columnconfigure(1, weight=1)
self.canvas = tk.Canvas(self, highlightthickness=0)
self.canvas.grid(row=0, columnspan=2, sticky="nsew", padx=2, pady=2)
self.canvas.columnconfigure(0, weight=1)
self.canvas.rowconfigure(0, weight=1)
self.scrollbar = tk.Scrollbar(
self, orient="vertical", command=self.canvas.yview
)
self.scrollbar.grid(row=0, column=2, sticky="ns")
self.frame = tk.Frame(self.canvas, padx=2, pady=2)
self.frame.columnconfigure(0, weight=1)
self.frame_id = self.canvas.create_window(0, 0, anchor="nw", window=self.frame)
self.canvas.update_idletasks()
self.canvas.configure(
scrollregion=self.canvas.bbox("all"), yscrollcommand=self.scrollbar.set
)
self.frame.bind(
"<Configure>",
lambda event: self.canvas.configure(scrollregion=self.canvas.bbox("all")),
)
self.canvas.bind(
"<Configure>",
lambda event: self.canvas.itemconfig(self.frame_id, width=event.width),
)
def clear(self):
for widget in self.frame.winfo_children():
widget.destroy()
class ListboxScroll(tk.LabelFrame):
def __init__(self, master=None, cnf={}, **kw):
super().__init__(master, cnf, **kw)
self.columnconfigure(0, weight=1)
self.rowconfigure(0, weight=1)
self.scrollbar = tk.Scrollbar(self, orient=tk.VERTICAL)
self.scrollbar.grid(row=0, column=1, sticky="ns")
self.listbox = tk.Listbox(
self, selectmode=tk.SINGLE, yscrollcommand=self.scrollbar.set
)
self.listbox.grid(row=0, column=0, sticky="nsew")
self.scrollbar.config(command=self.listbox.yview)
class CheckboxList(tk.LabelFrame):
def __init__(self, master=None, cnf={}, clicked=None, **kw):
super().__init__(master, cnf, **kw)
self.clicked = clicked
self.rowconfigure(0, weight=1)
self.columnconfigure(0, weight=1)
self.columnconfigure(1, weight=1)
self.canvas = tk.Canvas(self, highlightthickness=0)
self.canvas.grid(row=0, columnspan=2, sticky="nsew", padx=2, pady=2)
self.canvas.columnconfigure(0, weight=1)
self.canvas.rowconfigure(0, weight=1)
self.scrollbar = tk.Scrollbar(
self, orient="vertical", command=self.canvas.yview
)
self.scrollbar.grid(row=0, column=2, sticky="ns")
self.frame = tk.Frame(self.canvas, padx=2, pady=2)
self.frame.columnconfigure(0, weight=1)
self.frame_id = self.canvas.create_window(0, 0, anchor="nw", window=self.frame)
self.canvas.update_idletasks()
self.canvas.configure(
scrollregion=self.canvas.bbox("all"), yscrollcommand=self.scrollbar.set
)
self.frame.bind(
"<Configure>",
lambda event: self.canvas.configure(scrollregion=self.canvas.bbox("all")),
)
self.canvas.bind(
"<Configure>",
lambda event: self.canvas.itemconfig(self.frame_id, width=event.width),
)
def clear(self):
for widget in self.frame.winfo_children():
widget.destroy()
def add(self, name):
var = tk.BooleanVar()
func = partial(self.clicked, name, var)
checkbox = tk.Checkbutton(self.frame, text=name, variable=var, command=func)
checkbox.grid(sticky="w")