From 1dccceaf5695a7d025f985ec9f34219143790c2e Mon Sep 17 00:00:00 2001 From: Marek Wolan Date: Tue, 5 Sep 2023 15:53:22 +0100 Subject: [PATCH] Verify that action tree is starting to work! --- src/primaite/simulator/core.py | 6 ++-- .../simulator/network/hardware/base.py | 32 ++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/primaite/simulator/core.py b/src/primaite/simulator/core.py index e8cd4b98..f6c0b5d9 100644 --- a/src/primaite/simulator/core.py +++ b/src/primaite/simulator/core.py @@ -60,6 +60,9 @@ class Action(BaseModel): """ +# TODO: maybe this can be renamed to something like action selector? +# Because there are two ways it's used, to select from a list of action verbs, or to select a child object to which to +# forward the request. class ActionManager(BaseModel): """ ActionManager is used by `SimComponent` instances to keep track of actions. @@ -132,14 +135,13 @@ class ActionManager(BaseModel): self.actions.pop(name) - def get_action_tree(self) -> List[List[str]]: """Recursively generate action tree for this component.""" actions = [] for act_name, act in self.actions.items(): if isinstance(act.func, ActionManager): sub_actions = act.func.get_action_tree() - sub_actions = [[act_name]+a for a in sub_actions] + sub_actions = [[act_name] + a for a in sub_actions] actions.extend(sub_actions) else: actions.append([act_name]) diff --git a/src/primaite/simulator/network/hardware/base.py b/src/primaite/simulator/network/hardware/base.py index a846f7e2..e5f16323 100644 --- a/src/primaite/simulator/network/hardware/base.py +++ b/src/primaite/simulator/network/hardware/base.py @@ -10,7 +10,7 @@ from prettytable import MARKDOWN, PrettyTable from primaite import getLogger from primaite.exceptions import NetworkError -from primaite.simulator.core import SimComponent +from primaite.simulator.core import Action, ActionManager, SimComponent from primaite.simulator.domain.account import Account from primaite.simulator.file_system.file_system import FileSystem from primaite.simulator.network.protocols.arp import ARPEntry, ARPPacket @@ -145,6 +145,14 @@ class NIC(SimComponent): ) return state + def _init_action_manager(self) -> ActionManager: + am = super()._init_action_manager() + + am.add_action("enable", Action(func=lambda request, context: self.enable())) + am.add_action("disable", Action(func=lambda request, context: self.disable())) + + return am + @property def ip_network(self) -> IPv4Network: """ @@ -925,6 +933,24 @@ class Node(SimComponent): super().__init__(**kwargs) self.arp.nics = self.nics + def _init_action_manager(self) -> ActionManager: + # TODO: I see that this code is really confusing and hard to read right now... I think some of these things will + # need a better name and better documentation. + am = super()._init_action_manager() + # since there are potentially many services, create an action manager that can map service name + self._service_action_manager = ActionManager() + am.add_action("service", Action(func=self._service_action_manager)) + self._process_action_manager = ActionManager() + am.add_action("process", Action(func=self._process_action_manager)) + self._application_action_manager = ActionManager() + am.add_action("application", Action(func=self._application_action_manager)) + self._nic_action_manager = ActionManager() + am.add_action("nic", Action(func=self._nic_action_manager)) + + am.add_action("file_system", Action(func=self.file_system._action_manager)) + + return am + def describe_state(self) -> Dict: """ Produce a dictionary describing the current state of this object. @@ -1000,6 +1026,7 @@ class Node(SimComponent): self.sys_log.info(f"Connected NIC {nic}") if self.operating_state == NodeOperatingState.ON: nic.enable() + self._nic_action_manager.add_action(nic.uuid, Action(func=nic._action_manager)) else: msg = f"Cannot connect NIC {nic} as it is already connected" self.sys_log.logger.error(msg) @@ -1024,6 +1051,7 @@ class Node(SimComponent): nic.parent = None nic.disable() self.sys_log.info(f"Disconnected NIC {nic}") + self._nic_action_manager.remove_action(nic.uuid) else: msg = f"Cannot disconnect NIC {nic} as it is not connected" self.sys_log.logger.error(msg) @@ -1110,6 +1138,7 @@ class Node(SimComponent): service.install() # Perform any additional setup, such as creating files for this service on the node. self.sys_log.info(f"Installed service {service.name}") _LOGGER.info(f"Added service {service.uuid} to node {self.uuid}") + self._service_action_manager.add_action(service.uuid, Action(func=service._action_manager)) def uninstall_service(self, service: Service) -> None: """Uninstall and completely remove service from this node. @@ -1125,6 +1154,7 @@ class Node(SimComponent): service.parent = None self.sys_log.info(f"Uninstalled service {service.name}") _LOGGER.info(f"Removed service {service.uuid} from node {self.uuid}") + self._service_action_manager.remove_action(service.uuid) def __contains__(self, item: Any) -> bool: if isinstance(item, Service):