Skip to content

Commit

Permalink
daemon/gui: adjustments to support EMANE manifest parsing to use rege…
Browse files Browse the repository at this point in the history
…xes directly and check them within the GUI, small adjustment when writing out compose files to avoid removing single quotes
  • Loading branch information
bharnden committed Feb 7, 2024
1 parent 7d996ea commit 2e8bf71
Show file tree
Hide file tree
Showing 9 changed files with 35 additions and 30 deletions.
1 change: 1 addition & 0 deletions daemon/core/api/grpc/grpcutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ def get_config_options(
value=value,
type=configuration.type.value,
select=configuration.options,
regex=configuration.regex,
)
results[configuration.id] = config_option
for config_group in configurable_options.config_groups():
Expand Down
2 changes: 2 additions & 0 deletions daemon/core/api/grpc/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ class ConfigOption:
type: ConfigOptionType = None
group: str = None
select: list[str] = None
regex: str = None

@classmethod
def from_dict(
Expand All @@ -328,6 +329,7 @@ def from_proto(cls, proto: common_pb2.ConfigOption) -> "ConfigOption":
type=config_type,
group=proto.group,
select=list(proto.select),
regex=proto.regex,
)

def to_proto(self) -> common_pb2.ConfigOption:
Expand Down
1 change: 1 addition & 0 deletions daemon/core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class Configuration:
default: str = ""
options: list[str] = field(default_factory=list)
group: str = "Configuration"
regex: str = None

def __post_init__(self) -> None:
self.label = self.label if self.label else self.id
Expand Down
25 changes: 5 additions & 20 deletions daemon/core/emane/emanemanifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,6 @@ def _type_value(config_type: str) -> ConfigDataTypes:
return ConfigDataTypes[config_type]


def _get_possible(config_type: str, config_regex: str) -> list[str]:
"""
Retrieve possible config value options based on emane regexes.
:param config_type: emane configuration type
:param config_regex: emane configuration regex
:return: a string listing comma delimited values, if needed, empty string otherwise
"""
if config_type == "bool":
return ["On", "Off"]

if config_type == "string" and config_regex:
possible = config_regex[2:-2]
return possible.split("|")

return []


def _get_default(config_type_name: str, config_value: list[str]) -> str:
"""
Convert default configuration values to one used by core.
Expand Down Expand Up @@ -111,7 +93,9 @@ def parse(manifest_path: Path, defaults: dict[str, str]) -> list[Configuration]:

# map to possible values used as options within the gui
config_regex = config_info.get("regex")
possible = _get_possible(config_type_name, config_regex)
options = None
if config_type == "bool":
options = ["On", "Off"]

# define description and account for gui quirks
config_descriptions = config_name
Expand All @@ -122,8 +106,9 @@ def parse(manifest_path: Path, defaults: dict[str, str]) -> list[Configuration]:
id=config_name,
type=config_type_value,
default=config_default,
options=possible,
options=options,
label=config_descriptions,
regex=config_regex,
)
configurations.append(configuration)

Expand Down
13 changes: 8 additions & 5 deletions daemon/core/gui/dialogs/emaneconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
import tkinter as tk
import webbrowser
from tkinter import ttk
from tkinter import messagebox, ttk
from typing import TYPE_CHECKING, Optional

import grpc
Expand Down Expand Up @@ -70,10 +70,13 @@ def draw_buttons(self) -> None:
button.grid(row=0, column=1, sticky=tk.EW)

def click_apply(self) -> None:
self.config_frame.parse_config()
key = (self.model, self.iface_id)
self.node.emane_model_configs[key] = self.config
self.destroy()
try:
self.config_frame.parse_config()
key = (self.model, self.iface_id)
self.node.emane_model_configs[key] = self.config
self.destroy()
except ValueError as e:
messagebox.showerror("EMANE Config Error", str(e))


class EmaneConfigDialog(Dialog):
Expand Down
16 changes: 13 additions & 3 deletions daemon/core/gui/widgets.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import re
import tkinter as tk
from functools import partial
from pathlib import Path
Expand All @@ -9,6 +10,7 @@
from core.gui import appconfig, themes, validation
from core.gui.dialogs.dialog import Dialog
from core.gui.themes import FRAME_PAD, PADX, PADY
from core.gui.tooltip import Tooltip

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -41,7 +43,7 @@ def __init__(
master: tk.Widget,
app: "Application",
_cls: type[ttk.Frame] = ttk.Frame,
**kw: Any
**kw: Any,
) -> None:
super().__init__(master, **kw)
self.app: "Application" = app
Expand Down Expand Up @@ -88,7 +90,7 @@ def __init__(
app: "Application",
config: dict[str, ConfigOption],
enabled: bool = True,
**kw: Any
**kw: Any,
) -> None:
super().__init__(master, **kw)
self.app: "Application" = app
Expand Down Expand Up @@ -148,6 +150,8 @@ def draw_config(self) -> None:
else:
entry = ttk.Entry(tab.frame, textvariable=value, state=state)
entry.grid(row=index, column=1, sticky=tk.EW)
if option.regex:
Tooltip(entry, option.regex)
elif option.type in INT_TYPES:
value.set(option.value)
state = tk.NORMAL if self.enabled else tk.DISABLED
Expand Down Expand Up @@ -177,6 +181,12 @@ def parse_config(self) -> dict[str, str]:
else:
option.value = "0"
else:
if option.regex:
if not re.match(option.regex, config_value):
raise ValueError(
f"{option.label} value '{config_value}' "
f"does not match regex '{option.regex}'"
)
option.value = config_value
return {x: self.config[x].value for x in self.config}

Expand Down Expand Up @@ -216,7 +226,7 @@ def __init__(
master: ttk.Widget,
app: "Application",
clicked: Callable = None,
**kw: Any
**kw: Any,
) -> None:
super().__init__(master, app, **kw)
self.clicked: Callable = clicked
Expand Down
3 changes: 2 additions & 1 deletion daemon/core/nodes/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,10 @@ def startup(self) -> None:
data = self.host_cmd(f"cat {self.compose}")
template = Template(data)
rendered = template.render_unicode(node=self, hostname=hostname)
rendered = rendered.replace('"', r"\"")
rendered = "\\n".join(rendered.splitlines())
compose_path = self.directory / "docker-compose.yml"
self.host_cmd(f"printf '{rendered}' >> {compose_path}", shell=True)
self.host_cmd(f'printf "{rendered}" >> {compose_path}', shell=True)
self.host_cmd(
f"{DOCKER_COMPOSE} up -d {self.compose_name}",
cwd=self.directory,
Expand Down
3 changes: 2 additions & 1 deletion daemon/core/nodes/podman.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,10 @@ def startup(self) -> None:
data = self.host_cmd(f"cat {self.compose}")
template = Template(data)
rendered = template.render_unicode(node=self, hostname=hostname)
rendered = rendered.replace('"', r"\"")
rendered = "\\n".join(rendered.splitlines())
compose_path = self.directory / "podman-compose.yml"
self.host_cmd(f"printf '{rendered}' >> {compose_path}", shell=True)
self.host_cmd(f'printf "{rendered}" >> {compose_path}', shell=True)
self.host_cmd(f"{PODMAN_COMPOSE} up -d", cwd=self.directory)
else:
# setup commands for creating bind/volume mounts
Expand Down
1 change: 1 addition & 0 deletions daemon/proto/core/api/grpc/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ message ConfigOption {
int32 type = 4;
repeated string select = 5;
string group = 6;
string regex = 7;
}

message MappedConfig {
Expand Down

0 comments on commit 2e8bf71

Please sign in to comment.