Make changes to the way actions work

This commit is contained in:
Marek Wolan
2023-08-28 22:34:20 +01:00
parent a9e969aa13
commit 319e87d200
8 changed files with 83 additions and 70 deletions

View File

@@ -136,7 +136,7 @@ class SimComponent(BaseModel):
if not kwargs.get("uuid"):
kwargs["uuid"] = str(uuid4())
super().__init__(**kwargs)
self.action_manager: Optional[ActionManager] = None
self._action_manager: ActionManager = self._init_action_manager()
self._parent: Optional["SimComponent"] = None
@abstractmethod
@@ -153,6 +153,28 @@ class SimComponent(BaseModel):
}
return state
def _init_action_manager(self) -> ActionManager:
"""
Initialise the action manager for this component.
When using a hierarchy of components, the child classes should call the parent class's _init_action_manager and
add additional actions on top of the existing generic ones.
Example usage for inherited classes:
..code::python
class WebBrowser(Application):
def _init_action_manager(self) -> ActionManager:
am = super()._init_action_manager() # all actions generic to any Application get initialised
am.add_action(...) # initialise any actions specific to the web browser
return am
:return: Actiona manager object belonging to this sim component.
:rtype: ActionManager
"""
return ActionManager()
def apply_action(self, action: List[str], context: Dict = {}) -> None:
"""
Apply an action to a simulation component. Action data is passed in as a 'namespaced' list of strings.

View File

@@ -85,17 +85,6 @@ class DomainController(SimComponent):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.action_manager = ActionManager()
# Action 'account' matches requests like:
# ['account', '<account-uuid>', *account_action]
self.action_manager.add_action(
"account",
Action(
func=lambda request, context: self.accounts[request.pop(0)].apply_action(request, context),
validator=GroupMembershipValidator([AccountGroup.DOMAIN_ADMIN]),
),
)
def describe_state(self) -> Dict:
"""
Produce a dictionary describing the current state of this object.
@@ -109,6 +98,19 @@ class DomainController(SimComponent):
state.update({"accounts": {uuid: acct.describe_state() for uuid, acct in self.accounts.items()}})
return state
def _init_action_manager(self) -> ActionManager:
am = super()._init_action_manager()
# Action 'account' matches requests like:
# ['account', '<account-uuid>', *account_action]
am.add_action(
"account",
Action(
func=lambda request, context: self.accounts[request.pop(0)].apply_action(request, context),
validator=GroupMembershipValidator([AccountGroup.DOMAIN_ADMIN]),
),
)
return am
def _register_account(self, account: Account) -> None:
"""TODO."""
...

View File

@@ -17,15 +17,6 @@ class Network(SimComponent):
"""Initialise the network."""
super().__init__(**kwargs)
self.action_manager = ActionManager()
self.action_manager.add_action(
"node",
Action(
func=lambda request, context: self.nodes[request.pop(0)].apply_action(request, context),
validator=AllowAllValidator(),
),
)
def describe_state(self) -> Dict:
"""
Produce a dictionary describing the current state of this object.
@@ -44,6 +35,18 @@ class Network(SimComponent):
)
return state
def _init_action_manager(self) -> ActionManager:
am = super()._init_action_manager()
am.add_action(
"node",
Action(
func=lambda request, context: self.nodes[request.pop(0)].apply_action(request, context),
validator=AllowAllValidator(),
),
)
return am
def add_node(self, node: Node) -> None:
"""
Add an existing node to the network.

View File

@@ -21,22 +21,6 @@ class Simulation(SimComponent):
super().__init__(**kwargs)
self.action_manager = ActionManager()
# pass through network actions to the network objects
self.action_manager.add_action(
"network",
Action(
func=lambda request, context: self.network.apply_action(request, context), validator=AllowAllValidator()
),
)
# pass through domain actions to the domain object
self.action_manager.add_action(
"domain",
Action(
func=lambda request, context: self.domain.apply_action(request, context), validator=AllowAllValidator()
),
)
def describe_state(self) -> Dict:
"""
Produce a dictionary describing the current state of this object.
@@ -54,3 +38,21 @@ class Simulation(SimComponent):
}
)
return state
def _init_action_manager(self) -> ActionManager:
am = super()._init_action_manager()
# pass through network actions to the network objects
am.add_action(
"network",
Action(
func=lambda request, context: self.network.apply_action(request, context), validator=AllowAllValidator()
),
)
# pass through domain actions to the domain object
am.add_action(
"domain",
Action(
func=lambda request, context: self.domain.apply_action(request, context), validator=AllowAllValidator()
),
)
return am

View File

@@ -1,6 +1,6 @@
from abc import abstractmethod
from enum import Enum
from typing import Any, Dict, List, Set
from typing import Any, Dict, Set
from primaite.simulator.system.software import IOSoftware
@@ -53,14 +53,6 @@ class Application(IOSoftware):
)
return state
def apply_action(self, action: List[str]) -> None:
"""
Applies a list of actions to the Application.
:param action: A list of actions to apply.
"""
pass
def reset_component_for_episode(self, episode: int):
"""
Resets the Application component for a new episode.

View File

@@ -28,6 +28,8 @@ class DatabaseService(Service):
:param folder_name: Name of the folder which will be setup to hold the db files, defaults to "database"
:type folder_name: str, optional
"""
# note that this parent.file_system.create_folder call in the future will be authenticated by using permissions
# handler. This permission will be granted based on service account given to the database service.
folder = self.parent.file_system.create_folder(folder_name)
self.parent.file_system.create_file("db_primary_store", db_size, FileSystemFileType.MDF, folder=folder)
self.parent.file_system.create_file("db_transaction_log", "1", FileSystemFileType.LDF, folder=folder)

View File

@@ -2,7 +2,6 @@ from abc import abstractmethod
from enum import Enum
from typing import Any, Dict, List
from primaite.simulator.network.hardware.base import Node
from primaite.simulator.system.software import IOSoftware
@@ -33,17 +32,6 @@ class Service(IOSoftware):
operating_state: ServiceOperatingState
"The current operating state of the Service."
@abstractmethod
def __init__(self, parent_node: Node, **kwargs):
"""Create the service on a node.
:param parent_node: The node on which this service runs.
:type parent_node: Node
"""
super().__init__(**kwargs)
self.parent: Node = parent_node
self.parent.software_manager.add_service(self)
@abstractmethod
def describe_state(self) -> Dict:
"""

View File

@@ -1,6 +1,6 @@
from abc import abstractmethod
from enum import Enum
from typing import Any, Dict, List, Set
from typing import Any, Dict, Set
from primaite.simulator.core import SimComponent
from primaite.simulator.network.transmission.transport_layer import Port
@@ -98,17 +98,6 @@ class Software(SimComponent):
)
return state
def apply_action(self, action: List[str]) -> None:
"""
Applies a list of actions to the software.
The specifics of how these actions are applied should be implemented in subclasses.
:param action: A list of actions to apply.
:type action: List[str]
"""
pass
def reset_component_for_episode(self, episode: int):
"""
Resets the software component for a new episode.
@@ -119,6 +108,19 @@ class Software(SimComponent):
"""
pass
def set_health_state(self, health_state: SoftwareHealthState) -> None:
"""
Assign a new health state to this software.
Note: this should only be possible when the software is currently running, but the software base class has no
operating state, only subclasses do. So subclasses will need to implement this check. TODO: check if this should
be changed so that the base Software class has a running attr.
:param health_state: New health state to assign to the software
:type health_state: SoftwareHealthState
"""
self.health_state_actual = health_state
class IOSoftware(Software):
"""