From 0006bd4abc2ee9d911c76aeab446fb41506320c7 Mon Sep 17 00:00:00 2001 From: Huy Pham <42948410+hpham@users.noreply.github.com> Date: Fri, 15 Nov 2019 17:05:03 -0800 Subject: [PATCH] save service file data change locally and use that for display and for start session --- coretk/coretk/coreclient.py | 90 ++++++++++++++---- coretk/coretk/dialogs/nodeservice.py | 6 +- coretk/coretk/dialogs/serviceconfiguration.py | 94 ++++++++++++------- coretk/coretk/servicefileconfig.py | 37 ++++++++ coretk/coretk/servicenodeconfig.py | 5 +- 5 files changed, 177 insertions(+), 55 deletions(-) create mode 100644 coretk/coretk/servicefileconfig.py diff --git a/coretk/coretk/coreclient.py b/coretk/coretk/coreclient.py index 51aa8e46..52a45140 100644 --- a/coretk/coretk/coreclient.py +++ b/coretk/coretk/coreclient.py @@ -11,6 +11,7 @@ from coretk.emaneodelnodeconfig import EmaneModelNodeConfig from coretk.images import NODE_WIDTH, Images from coretk.interface import Interface, InterfaceManager from coretk.mobilitynodeconfig import MobilityNodeConfig +from coretk.servicefileconfig import ServiceFileConfig from coretk.servicenodeconfig import ServiceNodeConfig from coretk.wlannodeconfig import WlanNodeConfig @@ -126,6 +127,9 @@ class CoreClient: self.emaneconfig_management = EmaneModelNodeConfig(app) self.emane_config = None self.serviceconfig_manager = ServiceNodeConfig(app) + self.servicefileconfig_manager = ServiceFileConfig() + self.created_nodes = set() + self.created_links = set() def set_observer(self, value): self.observer = value @@ -345,6 +349,10 @@ class CoreClient: mobility_configs = self.get_mobility_configs_proto() emane_model_configs = self.get_emane_model_configs_proto() hooks = list(self.hooks.values()) + # service_configs = self.get_service_config_proto() + # service_file_configs = self.get_service_file_config_proto() + self.created_links.clear() + self.created_nodes.clear() if self.emane_config: emane_config = {x: self.emane_config[x].value for x in self.emane_config} else: @@ -358,16 +366,10 @@ class CoreClient: emane_config=emane_config, emane_model_configs=emane_model_configs, mobility_configs=mobility_configs, + # service_configs=service_configs ) logging.debug("Start session %s, result: %s", self.session_id, response.result) - response = self.client.get_service_defaults(self.session_id) - for default in response.defaults: - print(default.node_type) - print(default.services) - response = self.client.get_node_service(self.session_id, 5, "FTP") - print(response) - def stop_session(self): response = self.client.stop_session(session_id=self.session_id) logging.debug("coregrpc.py Stop session, result: %s", response.result) @@ -434,23 +436,42 @@ class CoreClient: logging.debug("get service file %s", response) return response.data + def set_node_service_file(self, node_id, service_name, file_name, data): + response = self.client.set_node_service_file( + self.session_id, node_id, service_name, file_name, data + ) + logging.debug("set node service file %s", response) + def create_nodes_and_links(self): + """ + create nodes and links that have not been created yet + + :return: nothing + """ node_protos = self.get_nodes_proto() link_protos = self.get_links_proto() - self.client.set_session_state(self.session_id, core_pb2.SessionState.DEFINITION) for node_proto in node_protos: - response = self.client.add_node(self.session_id, node_proto) - logging.debug("create node: %s", response) + if node_proto.id not in self.created_nodes: + response = self.client.add_node(self.session_id, node_proto) + logging.debug("create node: %s", response) + self.created_nodes.add(node_proto.id) for link_proto in link_protos: - response = self.client.add_link( - self.session_id, - link_proto.node_one_id, - link_proto.node_two_id, - link_proto.interface_one, - link_proto.interface_two, - link_proto.options, - ) - logging.debug("create link: %s", response) + if ( + tuple([link_proto.node_one_id, link_proto.node_two_id]) + not in self.created_links + ): + response = self.client.add_link( + self.session_id, + link_proto.node_one_id, + link_proto.node_two_id, + link_proto.interface_one, + link_proto.interface_two, + link_proto.options, + ) + logging.debug("create link: %s", response) + self.created_links.add( + tuple([link_proto.node_one_id, link_proto.node_two_id]) + ) def close(self): """ @@ -838,6 +859,37 @@ class CoreClient: configs.append(config_proto) return configs + def get_service_config_proto(self): + configs = [] + for ( + node_id, + service_configs, + ) in self.serviceconfig_manager.configurations.items(): + for service, config in service_configs.items(): + config = core_pb2.ServiceConfig( + node_id=node_id, + service=service, + startup=config.startup, + validate=config.validate, + shutdown=config.shutdown, + ) + configs.append(config) + return configs + + def get_service_file_config_proto(self): + configs = [] + for ( + node_id, + service_file_configs, + ) in self.servicefileconfig_manager.configurations.items(): + for service, file_configs in service_file_configs.items(): + for file, data in file_configs.items(): + config = core_pb2.ServiceFileConfig( + node_id=node_id, service=service, file=file, data=data + ) + configs.append(config) + return configs + def run(self, node_id): logging.info("running node(%s) cmd: %s", node_id, self.observer) return self.client.node_command(self.session_id, node_id, self.observer).output diff --git a/coretk/coretk/dialogs/nodeservice.py b/coretk/coretk/dialogs/nodeservice.py index 9ced9205..d791cc0e 100644 --- a/coretk/coretk/dialogs/nodeservice.py +++ b/coretk/coretk/dialogs/nodeservice.py @@ -17,7 +17,11 @@ class NodeService(Dialog): self.services = None self.current = None if services is None: - services = set() + services = set( + app.core.serviceconfig_manager.configurations[ + canvas_node.core_id + ].keys() + ) self.current_services = services self.draw() diff --git a/coretk/coretk/dialogs/serviceconfiguration.py b/coretk/coretk/dialogs/serviceconfiguration.py index 360e9561..da0c0736 100644 --- a/coretk/coretk/dialogs/serviceconfiguration.py +++ b/coretk/coretk/dialogs/serviceconfiguration.py @@ -15,6 +15,7 @@ class ServiceConfiguration(Dialog): super().__init__(master, app, f"{service_name} service", modal=True) self.app = app self.canvas_node = canvas_node + self.node_id = canvas_node.core_id self.service_name = service_name self.radiovar = tk.IntVar() self.radiovar.set(2) @@ -40,8 +41,9 @@ class ServiceConfiguration(Dialog): self.validation_time_entry = None self.validation_mode_entry = None self.service_file_data = None - self.service_files = {} + self.original_service_files = {} self.temp_service_files = {} + self.modified_files = set() self.load() self.draw() @@ -49,9 +51,18 @@ class ServiceConfiguration(Dialog): # create nodes and links in definition state for getting and setting service file self.app.core.create_nodes_and_links() # load data from local memory - service_config = self.app.core.serviceconfig_manager.configurations[ - self.canvas_node.core_id - ][self.service_name] + serviceconfig_manager = self.app.core.serviceconfig_manager + if self.service_name in serviceconfig_manager.configurations[self.node_id]: + service_config = serviceconfig_manager.configurations[self.node_id][ + self.service_name + ] + else: + serviceconfig_manager.node_custom_service_configuration( + self.node_id, self.service_name + ) + service_config = serviceconfig_manager.configurations[self.node_id][ + self.service_name + ] self.dependencies = [x for x in service_config.dependencies] self.executables = [x for x in service_config.executables] self.metadata = service_config.meta @@ -61,13 +72,24 @@ class ServiceConfiguration(Dialog): self.shutdown_commands = [x for x in service_config.shutdown] self.validation_mode = service_config.validation_mode self.validation_time = service_config.validation_timer - self.service_files = { + self.original_service_files = { x: self.app.core.get_node_service_file( self.canvas_node.core_id, self.service_name, x ) for x in self.filenames } - self.temp_service_files = self.service_files + self.temp_service_files = { + x: self.original_service_files[x] for x in self.original_service_files + } + configs = self.app.core.servicefileconfig_manager.configurations + if ( + self.canvas_node.core_id in configs + and self.service_name in configs[self.canvas_node.core_id] + ): + for file, data in configs[self.canvas_node.core_id][ + self.service_name + ].items(): + self.temp_service_files[file] = data def draw(self): # self.columnconfigure(1, weight=1) @@ -169,7 +191,10 @@ class ServiceConfiguration(Dialog): if len(self.filenames) > 0: self.filename_combobox.current(0) self.service_file_data.delete(1.0, "end") - self.service_file_data.insert("end", self.service_files[self.filenames[0]]) + self.service_file_data.insert( + "end", self.temp_service_files[self.filenames[0]] + ) + self.service_file_data.bind("", self.update_temp_service_file_data) # tab 2 label = ttk.Label( @@ -184,7 +209,6 @@ class ServiceConfiguration(Dialog): if i == 0: label_frame = ttk.LabelFrame(tab3, text="Startup commands") commands = self.startup_commands - elif i == 1: label_frame = ttk.LabelFrame(tab3, text="Shutdown commands") commands = self.shutdown_commands @@ -242,11 +266,9 @@ class ServiceConfiguration(Dialog): frame.columnconfigure(0, weight=1) if i == 0: label = ttk.Label(frame, text="Validation time:") - self.validation_time_entry = ttk.Entry( - frame, - state="disabled", - textvariable=tk.StringVar(value=self.validation_time), - ) + self.validation_time_entry = ttk.Entry(frame) + self.validation_time_entry.insert("end", self.validation_time) + self.validation_time_entry.config(state="disabled") self.validation_time_entry.grid(row=i, column=1) elif i == 1: label = ttk.Label(frame, text="Validation mode:") @@ -258,13 +280,11 @@ class ServiceConfiguration(Dialog): mode = "NON_BLOCKING" elif self.validation_mode == core_pb2.ServiceValidationMode.TIMER: mode = "TIMER" - print("the mode is", mode) self.validation_mode_entry = ttk.Entry( frame, textvariable=tk.StringVar(value=mode) ) self.validation_mode_entry.insert("end", mode) - print("get mode") - print(self.validation_mode_entry.get()) + self.validation_mode_entry.config(state="disabled") self.validation_mode_entry.grid(row=i, column=1) elif i == 2: label = ttk.Label(frame, text="Validation period:") @@ -347,8 +367,6 @@ class ServiceConfiguration(Dialog): entry.delete(0, tk.END) def click_apply(self): - metadata = self.metadata_entry.get() - filenames = list(self.filename_combobox["values"]) startup_commands = self.startup_commands_listbox.get(0, "end") shutdown_commands = self.shutdown_commands_listbox.get(0, "end") validate_commands = self.validate_commands_listbox.get(0, "end") @@ -359,27 +377,35 @@ class ServiceConfiguration(Dialog): validate_commands, shutdown_commands, ) - filename = self.filename_combobox.get() - file_data = self.service_file_data.get() - print(filename, file_data) - logging.info( - "%s, %s, %s, %s, %s", - metadata, - filenames, - startup_commands, - shutdown_commands, - validate_commands, - ) - # wipe nodes and links when finished by setting to DEFINITION state - self.app.core.client.set_session_state( - self.app.core.session_id, core_pb2.SessionState.DEFINITION - ) + for file in self.modified_files: + self.app.core.servicefileconfig_manager.set_custom_service_file_config( + self.canvas_node.core_id, + self.service_name, + file, + self.temp_service_files[file], + ) + self.app.core.set_node_service_file( + self.canvas_node.core_id, + self.service_name, + file, + self.temp_service_files[file], + ) + self.destroy() def display_service_file_data(self, event): combobox = event.widget filename = combobox.get() self.service_file_data.delete(1.0, "end") - self.service_file_data.insert("end", self.service_files[filename]) + self.service_file_data.insert("end", self.temp_service_files[filename]) + + def update_temp_service_file_data(self, event): + scrolledtext = event.widget + filename = self.filename_combobox.get() + self.temp_service_files[filename] = scrolledtext.get(1.0, "end") + if self.temp_service_files[filename] != self.original_service_files[filename]: + self.modified_files.add(filename) + else: + self.modified_files.discard(filename) def click_defaults(self): logging.info("not implemented") diff --git a/coretk/coretk/servicefileconfig.py b/coretk/coretk/servicefileconfig.py new file mode 100644 index 00000000..06a134cd --- /dev/null +++ b/coretk/coretk/servicefileconfig.py @@ -0,0 +1,37 @@ +""" +service file configuration +""" + + +class ServiceFileConfig: + def __init__(self): + # dict(node_id:dict(service:dict(filename, data))) + self.configurations = {} + + # def set_service_configs(self, node_id, service_name, file_configs): + # """ + # store file configs + # + # :param int node_id: node id + # :param str service_name: service name + # :param dict(str, str) file_configs: map of service file to its data + # :return: nothing + # """ + # for key, value in file_configs.items(): + # self.configurations[node_id][service_name][key] = value + + def set_custom_service_file_config(self, node_id, service_name, file_name, data): + """ + store file config + + :param int node_id: node id + :param str service_name: service name + :param str file_name: file name + :param str data: data + :return: nothing + """ + if node_id not in self.configurations: + self.configurations[node_id] = {} + if service_name not in self.configurations[node_id]: + self.configurations[node_id][service_name] = {} + self.configurations[node_id][service_name][file_name] = data diff --git a/coretk/coretk/servicenodeconfig.py b/coretk/coretk/servicenodeconfig.py index f9c2ee88..98de9034 100644 --- a/coretk/coretk/servicenodeconfig.py +++ b/coretk/coretk/servicenodeconfig.py @@ -7,6 +7,7 @@ import logging class ServiceNodeConfig: def __init__(self, app): self.app = app + # dict(node_id:dict(service:node_service_config_proto)) self.configurations = {} self.default_services = {} @@ -37,7 +38,9 @@ class ServiceNodeConfig: self.configurations[node_id][default] = response.service def node_custom_service_configuration(self, node_id, service_name): - return + self.configurations[node_id][service_name] = self.app.core.get_node_service( + node_id, service_name + ) def node_service_custom_configuration( self, node_id, service_name, startups, validates, shutdowns