core-extra/daemon/core/gui/dialogs/linkconfig.py

362 lines
13 KiB
Python
Raw Normal View History

2019-12-17 19:47:05 +00:00
"""
link configuration
"""
import tkinter as tk
from tkinter import ttk
2020-01-13 23:31:41 +00:00
from typing import TYPE_CHECKING, Union
2019-12-17 19:47:05 +00:00
from core.api.grpc import core_pb2
from core.gui.dialogs.colorpicker import ColorPickerDialog
2019-12-19 17:30:21 +00:00
from core.gui.dialogs.dialog import Dialog
from core.gui.themes import PADX, PADY
2019-12-17 19:47:05 +00:00
2020-01-13 23:31:41 +00:00
if TYPE_CHECKING:
from core.gui.app import Application
2020-01-14 19:06:52 +00:00
from core.gui.graph.graph import CanvasGraph, CanvasEdge
2020-01-13 23:31:41 +00:00
2019-12-17 19:47:05 +00:00
def get_int(var: tk.StringVar) -> Union[int, None]:
value = var.get()
if value != "":
return int(value)
else:
return None
2020-01-13 23:31:41 +00:00
def get_float(var: tk.StringVar) -> Union[float, None]:
value = var.get()
if value != "":
return float(value)
else:
return None
class LinkConfigurationDialog(Dialog):
2020-01-14 19:06:52 +00:00
def __init__(self, master: "CanvasGraph", app: "Application", edge: "CanvasEdge"):
super().__init__(master, app, "Link Configuration", modal=True)
2019-12-17 19:47:05 +00:00
self.app = app
self.edge = edge
self.is_symmetric = edge.link.options.unidirectional is False
2019-12-17 19:47:05 +00:00
if self.is_symmetric:
self.symmetry_var = tk.StringVar(value=">>")
else:
self.symmetry_var = tk.StringVar(value="<<")
self.bandwidth = tk.StringVar()
self.delay = tk.StringVar()
self.jitter = tk.StringVar()
self.loss = tk.StringVar()
self.duplicate = tk.StringVar()
self.down_bandwidth = tk.StringVar()
self.down_delay = tk.StringVar()
self.down_jitter = tk.StringVar()
self.down_loss = tk.StringVar()
self.down_duplicate = tk.StringVar()
2019-12-17 19:59:34 +00:00
self.color = tk.StringVar(value="#000000")
self.color_button = None
2019-12-17 19:47:05 +00:00
self.width = tk.DoubleVar()
self.load_link_config()
self.symmetric_frame = None
self.asymmetric_frame = None
self.draw()
def draw(self):
self.top.columnconfigure(0, weight=1)
source_name = self.app.canvas.nodes[self.edge.src].core_node.name
dest_name = self.app.canvas.nodes[self.edge.dst].core_node.name
label = ttk.Label(
self.top, text=f"Link from {source_name} to {dest_name}", anchor=tk.CENTER
2019-12-17 19:47:05 +00:00
)
label.grid(row=0, column=0, sticky="ew", pady=PADY)
2019-12-17 19:47:05 +00:00
frame = ttk.Frame(self.top)
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=1)
frame.grid(row=1, column=0, sticky="ew", pady=PADY)
button = ttk.Button(frame, text="Unlimited")
button.grid(row=0, column=0, sticky="ew", padx=PADX)
2019-12-17 19:47:05 +00:00
if self.is_symmetric:
button = ttk.Button(
frame, textvariable=self.symmetry_var, command=self.change_symmetry
)
else:
button = ttk.Button(
frame, textvariable=self.symmetry_var, command=self.change_symmetry
)
button.grid(row=0, column=1, sticky="ew")
2019-12-17 19:47:05 +00:00
if self.is_symmetric:
self.symmetric_frame = self.get_frame()
self.symmetric_frame.grid(row=2, column=0, sticky="ew", pady=PADY)
2019-12-17 19:47:05 +00:00
else:
self.asymmetric_frame = self.get_frame()
self.asymmetric_frame.grid(row=2, column=0, sticky="ew", pady=PADY)
self.draw_spacer(row=3)
2019-12-17 19:47:05 +00:00
frame = ttk.Frame(self.top)
frame.columnconfigure(0, weight=1)
frame.columnconfigure(1, weight=1)
frame.grid(row=4, column=0, sticky="ew")
button = ttk.Button(frame, text="Apply", command=self.click_apply)
button.grid(row=0, column=0, sticky="ew", padx=PADX)
2019-12-17 19:47:05 +00:00
button = ttk.Button(frame, text="Cancel", command=self.destroy)
button.grid(row=0, column=1, sticky="ew")
2019-12-17 19:47:05 +00:00
def get_frame(self) -> ttk.Frame:
frame = ttk.Frame(self.top)
frame.columnconfigure(1, weight=1)
2019-12-17 19:47:05 +00:00
if self.is_symmetric:
label_name = "Symmetric Link Effects"
2019-12-17 19:47:05 +00:00
else:
label_name = "Asymmetric Effects: Downstream / Upstream "
2019-12-17 19:47:05 +00:00
row = 0
label = ttk.Label(frame, text=label_name, anchor=tk.CENTER)
label.grid(row=row, column=0, columnspan=2, sticky="ew", pady=PADY)
2019-12-17 19:47:05 +00:00
row = row + 1
label = ttk.Label(frame, text="Bandwidth (bps)")
label.grid(row=row, column=0, sticky="ew")
entry = ttk.Entry(
frame,
textvariable=self.bandwidth,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
2019-12-17 19:47:05 +00:00
if not self.is_symmetric:
entry = ttk.Entry(
frame,
textvariable=self.down_bandwidth,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
2019-12-17 19:47:05 +00:00
row = row + 1
label = ttk.Label(frame, text="Delay (us)")
label.grid(row=row, column=0, sticky="ew")
entry = ttk.Entry(
frame,
textvariable=self.delay,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
2019-12-17 19:47:05 +00:00
if not self.is_symmetric:
entry = ttk.Entry(
frame,
textvariable=self.down_delay,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
2019-12-17 19:47:05 +00:00
row = row + 1
label = ttk.Label(frame, text="Jitter (us)")
label.grid(row=row, column=0, sticky="ew")
entry = ttk.Entry(
frame,
textvariable=self.jitter,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
2019-12-17 19:47:05 +00:00
if not self.is_symmetric:
entry = ttk.Entry(
frame,
textvariable=self.down_jitter,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
2019-12-17 19:47:05 +00:00
row = row + 1
label = ttk.Label(frame, text="Loss (%)")
label.grid(row=row, column=0, sticky="ew")
entry = ttk.Entry(
frame,
textvariable=self.loss,
validate="key",
validatecommand=(self.app.validation.positive_float, "%P"),
)
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
2019-12-17 19:47:05 +00:00
if not self.is_symmetric:
entry = ttk.Entry(
frame,
textvariable=self.down_loss,
validate="key",
validatecommand=(self.app.validation.positive_float, "%P"),
)
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
2019-12-17 19:47:05 +00:00
row = row + 1
label = ttk.Label(frame, text="Duplicate (%)")
label.grid(row=row, column=0, sticky="ew")
entry = ttk.Entry(
frame,
textvariable=self.duplicate,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
2019-12-17 19:47:05 +00:00
if not self.is_symmetric:
entry = ttk.Entry(
frame,
textvariable=self.down_duplicate,
validate="key",
validatecommand=(self.app.validation.positive_int, "%P"),
)
entry.grid(row=row, column=2, sticky="ew", pady=PADY)
2019-12-17 19:47:05 +00:00
row = row + 1
label = ttk.Label(frame, text="Color")
label.grid(row=row, column=0, sticky="ew")
self.color_button = tk.Button(
frame,
textvariable=self.color,
background=self.color.get(),
bd=0,
relief=tk.FLAT,
highlightthickness=0,
command=self.click_color,
)
self.color_button.grid(row=row, column=1, sticky="ew", pady=PADY)
2019-12-17 19:47:05 +00:00
row = row + 1
label = ttk.Label(frame, text="Width")
label.grid(row=row, column=0, sticky="ew")
entry = ttk.Entry(
frame,
textvariable=self.width,
validate="key",
validatecommand=(self.app.validation.positive_float, "%P"),
)
entry.grid(row=row, column=1, sticky="ew", pady=PADY)
return frame
2019-12-17 19:47:05 +00:00
def click_color(self):
dialog = ColorPickerDialog(self, self.app, self.color.get())
color = dialog.askcolor()
self.color.set(color)
self.color_button.config(background=color)
2019-12-17 19:47:05 +00:00
def click_apply(self):
self.app.canvas.itemconfigure(self.edge.id, width=self.width.get())
self.app.canvas.itemconfigure(self.edge.id, fill=self.color.get())
link = self.edge.link
bandwidth = get_int(self.bandwidth)
jitter = get_int(self.jitter)
delay = get_int(self.delay)
duplicate = get_int(self.duplicate)
loss = get_float(self.loss)
options = core_pb2.LinkOptions(
bandwidth=bandwidth, jitter=jitter, delay=delay, dup=duplicate, per=loss
)
link.options.CopyFrom(options)
interface_one = None
if link.HasField("interface_one"):
interface_one = link.interface_one.id
interface_two = None
if link.HasField("interface_two"):
interface_two = link.interface_two.id
if not self.is_symmetric:
link.options.unidirectional = True
asym_interface_one = None
if interface_one:
asym_interface_one = core_pb2.Interface(id=interface_one)
asym_interface_two = None
if interface_two:
asym_interface_two = core_pb2.Interface(id=interface_two)
down_bandwidth = get_int(self.down_bandwidth)
down_jitter = get_int(self.down_jitter)
down_delay = get_int(self.down_delay)
down_duplicate = get_int(self.down_duplicate)
down_loss = get_float(self.down_loss)
options = core_pb2.LinkOptions(
bandwidth=down_bandwidth,
jitter=down_jitter,
delay=down_delay,
dup=down_duplicate,
per=down_loss,
unidirectional=True,
)
self.edge.asymmetric_link = core_pb2.Link(
node_one_id=link.node_two_id,
node_two_id=link.node_one_id,
interface_one=asym_interface_one,
interface_two=asym_interface_two,
options=options,
)
else:
link.options.unidirectional = False
self.edge.asymmetric_link = None
if self.app.core.is_runtime() and link.HasField("options"):
session_id = self.app.core.session_id
self.app.core.client.edit_link(
session_id,
link.node_one_id,
link.node_two_id,
link.options,
interface_one,
interface_two,
)
if self.edge.asymmetric_link:
self.app.core.client.edit_link(
session_id,
link.node_two_id,
link.node_one_id,
self.edge.asymmetric_link.options,
interface_one,
interface_two,
)
2019-12-17 19:59:34 +00:00
self.destroy()
2019-12-17 19:47:05 +00:00
def change_symmetry(self):
if self.is_symmetric:
self.is_symmetric = False
self.symmetry_var.set("<<")
if not self.asymmetric_frame:
self.asymmetric_frame = self.get_frame()
self.symmetric_frame.grid_forget()
self.asymmetric_frame.grid(row=2, column=0)
else:
self.is_symmetric = True
self.symmetry_var.set(">>")
if not self.symmetric_frame:
self.symmetric_frame = self.get_frame()
self.asymmetric_frame.grid_forget()
self.symmetric_frame.grid(row=2, column=0)
def load_link_config(self):
"""
populate link config to the table
"""
width = self.app.canvas.itemcget(self.edge.id, "width")
self.width.set(width)
color = self.app.canvas.itemcget(self.edge.id, "fill")
self.color.set(color)
link = self.edge.link
if link.HasField("options"):
self.bandwidth.set(str(link.options.bandwidth))
self.jitter.set(str(link.options.jitter))
self.duplicate.set(str(link.options.dup))
self.loss.set(str(link.options.per))
self.delay.set(str(link.options.delay))
if not self.is_symmetric:
asym_link = self.edge.asymmetric_link
self.down_bandwidth.set(str(asym_link.options.bandwidth))
self.down_jitter.set(str(asym_link.options.jitter))
self.down_duplicate.set(str(asym_link.options.dup))
self.down_loss.set(str(asym_link.options.per))
self.down_delay.set(str(asym_link.options.delay))