added files to config services, added default logic for creating files from templates, added new method to provide extra data to templates, updated gui to display templates raw

This commit is contained in:
Blake Harnden 2020-01-20 15:02:04 -08:00
parent 9447ddb94f
commit 7b5df11dc7
11 changed files with 120 additions and 52 deletions

View file

@ -15,6 +15,8 @@ from core.api.grpc import core_pb2, core_pb2_grpc
from core.api.grpc.configservices_pb2 import (
GetConfigServicesRequest,
GetConfigServicesResponse,
GetConfigServiceTemplatesRequest,
GetConfigServiceTemplatesResponse,
GetNodeConfigServiceRequest,
GetNodeConfigServiceResponse,
GetNodeConfigServicesRequest,
@ -1092,6 +1094,12 @@ class CoreGrpcClient:
request = GetConfigServicesRequest()
return self.stub.GetConfigServices(request)
def get_config_service_templates(
self, name: str
) -> GetConfigServiceTemplatesResponse:
request = GetConfigServiceTemplatesRequest(name=name)
return self.stub.GetConfigServiceTemplates(request)
def get_node_config_service(
self, session_id: int, node_id: int, name: str
) -> GetNodeConfigServiceResponse:

View file

@ -5,6 +5,7 @@ import re
import tempfile
import time
from concurrent import futures
from typing import Type
import grpc
from grpc import ServicerContext
@ -14,6 +15,8 @@ from core.api.grpc.configservices_pb2 import (
ConfigService,
GetConfigServicesRequest,
GetConfigServicesResponse,
GetConfigServiceTemplatesRequest,
GetConfigServiceTemplatesResponse,
GetNodeConfigServiceRequest,
GetNodeConfigServiceResponse,
GetNodeConfigServicesRequest,
@ -112,9 +115,13 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
except CoreError:
context.abort(grpc.StatusCode.NOT_FOUND, f"node {node_id} not found")
def validate_service(self, name: str, context: ServicerContext) -> None:
if name not in self.coreemu.service_manager.services:
def validate_service(
self, name: str, context: ServicerContext
) -> Type[ConfigService]:
service = self.coreemu.service_manager.services.get(name)
if not service:
context.abort(grpc.StatusCode.NOT_FOUND, f"unknown service {name}")
return service
def StartSession(
self, request: core_pb2.StartSessionRequest, context: ServicerContext
@ -1456,6 +1463,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
executables=service.executables,
dependencies=service.dependencies,
directories=service.directories,
files=service.files,
startup=service.startup,
validate=service.validate,
shutdown=service.shutdown,
@ -1481,6 +1489,14 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
config = {x.id: x.default for x in service.default_configs}
return GetNodeConfigServiceResponse(config=config)
def GetConfigServiceTemplates(
self, request: GetConfigServiceTemplatesRequest, context: ServicerContext
) -> GetConfigServiceTemplatesResponse:
service_class = self.validate_service(request.name, context)
service = service_class(None)
templates = service.get_templates()
return GetConfigServiceTemplatesResponse(templates=templates)
def GetNodeConfigServices(
self, request: GetNodeConfigServicesRequest, context: ServicerContext
) -> GetNodeConfigServicesResponse:

View file

@ -55,6 +55,11 @@ class ConfigService(abc.ABC):
def directories(self) -> List[str]:
raise NotImplementedError
@property
@abc.abstractmethod
def files(self) -> List[str]:
raise NotImplementedError
@property
@abc.abstractmethod
def default_configs(self) -> List[Configuration]:
@ -120,8 +125,34 @@ class ConfigService(abc.ABC):
f"failure to create service directory: {directory}"
)
def data(self) -> Dict[str, Any]:
return {}
def get_text(self, name: str) -> str:
raise CoreError(
f"node({self.node.name} service({self.name}) unknown template({name})"
)
def get_templates(self) -> Dict[str, str]:
templates = {}
for name in self.files:
if self.templates.has_template(name):
template = self.templates.get_template(name).source
else:
template = self.get_text(name)
template = inspect.cleandoc(template)
templates[name] = template
return templates
def create_files(self) -> None:
raise NotImplementedError
data = self.data()
for name in self.files:
if self.templates.has_template(name):
self.render_template(name, data)
else:
text = self.get_text(name)
text = inspect.cleandoc(text)
self.render_text(name, text, data)
def run_startup(self) -> None:
for cmd in self.startup:
@ -176,7 +207,6 @@ class ConfigService(abc.ABC):
def render_text(self, name: str, text: str, data: Dict[str, Any] = None) -> None:
try:
text = inspect.cleandoc(text)
template = Template(text)
self._render(name, template, data)
except Exception:

View file

@ -7,6 +7,7 @@ class VpnClient(ConfigService):
name = "VPNClient"
group = GROUP_NAME
directories = []
files = ["vpnclient.sh"]
executables = ["openvpn", "ip", "killall"]
dependencies = []
startup = ["sh vpnclient.sh"]
@ -14,6 +15,3 @@ class VpnClient(ConfigService):
shutdown = ["killall openvpn"]
validation_mode = ConfigServiceMode.BLOCKING
default_configs = []
def create_files(self):
self.render_template("vpnclient.sh")

View file

@ -1,3 +1,5 @@
from typing import Any, Dict
import netaddr
from core import utils
@ -12,6 +14,7 @@ class DefaultRoute(ConfigService):
name = "DefaultRoute"
group = GROUP_NAME
directories = []
files = ["defaultroute.sh"]
executables = ["ip"]
dependencies = []
startup = ["sh defaultroute.sh"]
@ -24,7 +27,7 @@ class DefaultRoute(ConfigService):
Configuration(_id="value3", _type=ConfigDataTypes.STRING, label="Value 3"),
]
def create_files(self):
def data(self) -> Dict[str, Any]:
addresses = []
for netif in self.node.netifs():
if getattr(netif, "control", False):
@ -33,14 +36,14 @@ class DefaultRoute(ConfigService):
net = netaddr.IPNetwork(addr)
if net[1] != net[-2]:
addresses.append(net[1])
data = dict(addresses=addresses)
self.render_template("defaultroute.sh", data)
return dict(addresses=addresses)
class IpForwardService(ConfigService):
name = "IPForward"
group = GROUP_NAME
directories = []
files = ["ipforward.sh"]
executables = ["sysctl"]
dependencies = []
startup = ["sh ipforward.sh"]
@ -49,10 +52,9 @@ class IpForwardService(ConfigService):
validation_mode = ConfigServiceMode.BLOCKING
default_configs = []
def create_files(self) -> None:
def data(self) -> Dict[str, Any]:
devnames = []
for ifc in self.node.netifs():
devname = utils.sysctl_devname(ifc.name)
devnames.append(devname)
data = dict(devnames=devnames)
self.render_template("ipforward.sh", data)
return dict(devnames=devnames)

View file

@ -5,6 +5,7 @@ class SimpleService(ConfigService):
name = "Simple"
group = "SimpleGroup"
directories = []
files = ["test1.sh"]
executables = []
dependencies = []
startup = []
@ -13,10 +14,10 @@ class SimpleService(ConfigService):
validation_mode = ConfigServiceMode.BLOCKING
default_configs = []
def create_files(self):
text = """
def get_text(self, name: str) -> str:
if name == "test1.sh":
return """
# sample script
# node id(${node.id}) name(${node.name})
echo hello
"""
self.render_text("test1.sh", text)

View file

@ -63,6 +63,7 @@ class CoreClient:
self.app = app
self.master = app.master
self.services = {}
self.config_services_groups = {}
self.config_services = {}
self.default_services = {}
self.emane_models = []
@ -417,7 +418,10 @@ class CoreClient:
# get config service informations
response = self.client.get_config_services()
for service in response.services:
group_services = self.config_services.setdefault(service.group, set())
self.config_services[service.name] = service
group_services = self.config_services_groups.setdefault(
service.group, set()
)
group_services.add(service.name)
# if there are no sessions, create a new session, else join a session

View file

@ -46,7 +46,7 @@ class ConfigServiceConfigDialog(Dialog):
self.default_shutdown = []
self.validation_mode = None
self.validation_time = None
self.validation_period = None
self.validation_period = tk.StringVar()
self.documentnew_img = Images.get(ImageEnum.DOCUMENTNEW, 16)
self.editdelete_img = Images.get(ImageEnum.EDITDELETE, 16)
@ -68,35 +68,33 @@ class ConfigServiceConfigDialog(Dialog):
def load(self):
try:
self.app.core.create_nodes_and_links()
default_config = self.app.core.get_node_service(
self.node_id, self.service_name
)
self.default_startup = default_config.startup[:]
self.default_validate = default_config.validate[:]
self.default_shutdown = default_config.shutdown[:]
custom_configs = self.service_configs
if (
self.node_id in custom_configs
and self.service_name in custom_configs[self.node_id]
):
service_config = custom_configs[self.node_id][self.service_name]
else:
service_config = default_config
# default_config = self.app.core.get_node_service(
# self.node_id, self.service_name
# )
# self.default_startup = default_config.startup[:]
# self.default_validate = default_config.validate[:]
# self.default_shutdown = default_config.shutdown[:]
# custom_configs = self.service_configs
# if (
# self.node_id in custom_configs
# and self.service_name in custom_configs[self.node_id]
# ):
# service_config = custom_configs[self.node_id][self.service_name]
# else:
# service_config = default_config
service_config = self.core.config_services[self.service_name]
self.dependencies = service_config.dependencies[:]
self.executables = service_config.executables[:]
self.filenames = service_config.configs[:]
self.filenames = service_config.files[:]
self.startup_commands = service_config.startup[:]
self.validation_commands = service_config.validate[:]
self.shutdown_commands = service_config.shutdown[:]
self.validation_mode = service_config.validation_mode
self.validation_time = service_config.validation_timer
self.original_service_files = {
x: self.app.core.get_node_service_file(
self.node_id, self.service_name, x
)
for x in self.filenames
}
self.validation_period.set(service_config.validation_period)
response = self.core.client.get_config_service_templates(self.service_name)
self.original_service_files = response.templates
self.temp_service_files = dict(self.original_service_files)
file_configs = self.file_configs
if (
@ -303,7 +301,7 @@ class ConfigServiceConfigDialog(Dialog):
label = ttk.Label(frame, text="Validation Period")
label.grid(row=2, column=0, sticky="w", padx=PADX)
self.validation_period_entry = ttk.Entry(
frame, state=tk.DISABLED, textvariable=tk.StringVar()
frame, state=tk.DISABLED, textvariable=self.validation_period
)
self.validation_period_entry.grid(row=2, column=1, sticky="ew", pady=PADY)

View file

@ -51,7 +51,7 @@ class NodeConfigServiceDialog(Dialog):
label_frame.columnconfigure(0, weight=1)
self.groups = ListboxScroll(label_frame)
self.groups.grid(sticky="nsew")
for group in sorted(self.app.core.config_services):
for group in sorted(self.app.core.config_services_groups):
self.groups.listbox.insert(tk.END, group)
self.groups.listbox.bind("<<ListboxSelect>>", self.handle_group_change)
self.groups.listbox.selection_set(0)
@ -98,7 +98,7 @@ class NodeConfigServiceDialog(Dialog):
index = selection[0]
group = self.groups.listbox.get(index)
self.services.clear()
for name in sorted(self.app.core.config_services[group]):
for name in sorted(self.app.core.config_services_groups[group]):
checked = name in self.current_services
self.services.add(name, checked)

View file

@ -16,12 +16,13 @@ message ConfigService {
repeated string executables = 3;
repeated string dependencies = 4;
repeated string directories = 5;
repeated string startup = 6;
repeated string validate = 7;
repeated string shutdown = 8;
ConfigServiceValidationMode.Enum validation_mode = 9;
int32 validation_timer = 10;
float validation_period = 11;
repeated string files = 6;
repeated string startup = 7;
repeated string validate = 8;
repeated string shutdown = 9;
ConfigServiceValidationMode.Enum validation_mode = 10;
int32 validation_timer = 11;
float validation_period = 12;
}
message GetConfigServicesRequest {
@ -32,6 +33,14 @@ message GetConfigServicesResponse {
repeated ConfigService services = 1;
}
message GetConfigServiceTemplatesRequest {
string name = 1;
}
message GetConfigServiceTemplatesResponse {
map<string, string> templates = 1;
}
message GetNodeConfigServiceRequest {
int32 session_id = 1;
int32 node_id = 2;

View file

@ -107,6 +107,8 @@ service CoreApi {
// config services
rpc GetConfigServices (configservices.GetConfigServicesRequest) returns (configservices.GetConfigServicesResponse) {
}
rpc GetConfigServiceTemplates (configservices.GetConfigServiceTemplatesRequest) returns (configservices.GetConfigServiceTemplatesResponse) {
}
rpc GetNodeConfigService (configservices.GetNodeConfigServiceRequest) returns (configservices.GetNodeConfigServiceResponse) {
}
rpc GetNodeConfigServices (configservices.GetNodeConfigServicesRequest) returns (configservices.GetNodeConfigServicesResponse) {