#1859 - First pass at an implementation of the full reset method. Will now start testing...
This commit is contained in:
@@ -38,6 +38,12 @@ class Application(IOSoftware):
|
||||
self.health_state_visible = SoftwareHealthState.UNUSED
|
||||
self.health_state_actual = SoftwareHealthState.UNUSED
|
||||
|
||||
def set_original_state(self):
|
||||
"""Sets the original state."""
|
||||
super().set_original_state()
|
||||
vals_to_include = {"operating_state", "execution_control_status", "num_executions", "groups"}
|
||||
self._original_state.update(self.model_dump(include=vals_to_include))
|
||||
|
||||
@abstractmethod
|
||||
def describe_state(self) -> Dict:
|
||||
"""
|
||||
@@ -82,15 +88,6 @@ class Application(IOSoftware):
|
||||
self.sys_log.info(f"Installing Application {self.name}")
|
||||
self.operating_state = ApplicationOperatingState.INSTALLING
|
||||
|
||||
def reset_component_for_episode(self, episode: int):
|
||||
"""
|
||||
Resets the Application component for a new episode.
|
||||
|
||||
This method ensures the Application is ready for a new episode, including resetting any
|
||||
stateful properties or statistics, and clearing any message queues.
|
||||
"""
|
||||
pass
|
||||
|
||||
def receive(self, payload: Any, session_id: str, **kwargs) -> bool:
|
||||
"""
|
||||
Receives a payload from the SessionManager.
|
||||
|
||||
@@ -31,6 +31,13 @@ class DatabaseClient(Application):
|
||||
kwargs["port"] = Port.POSTGRES_SERVER
|
||||
kwargs["protocol"] = IPProtocol.TCP
|
||||
super().__init__(**kwargs)
|
||||
self.set_original_state()
|
||||
|
||||
def set_original_state(self):
|
||||
"""Sets the original state."""
|
||||
super().set_original_state()
|
||||
vals_to_include = {"server_ip_address", "server_password", "connected"}
|
||||
self._original_state.update(self.model_dump(include=vals_to_include))
|
||||
|
||||
def describe_state(self) -> Dict:
|
||||
"""
|
||||
|
||||
@@ -33,8 +33,15 @@ class WebBrowser(Application):
|
||||
kwargs["port"] = Port.HTTP
|
||||
|
||||
super().__init__(**kwargs)
|
||||
self.set_original_state()
|
||||
self.run()
|
||||
|
||||
def set_original_state(self):
|
||||
"""Sets the original state."""
|
||||
super().set_original_state()
|
||||
vals_to_include = {"target_url", "domain_name_ip_address", "latest_response"}
|
||||
self._original_state.update(self.model_dump(include=vals_to_include))
|
||||
|
||||
def _init_request_manager(self) -> RequestManager:
|
||||
rm = super()._init_request_manager()
|
||||
rm.add_request(
|
||||
@@ -43,13 +50,6 @@ class WebBrowser(Application):
|
||||
|
||||
return rm
|
||||
|
||||
def do_this(self):
|
||||
self._init_request_manager()
|
||||
print(f"Resetting WebBrowser for episode")
|
||||
|
||||
def reset_component_for_episode(self, episode: int):
|
||||
pass
|
||||
|
||||
def describe_state(self) -> Dict:
|
||||
"""
|
||||
Produce a dictionary describing the current state of the WebBrowser.
|
||||
@@ -60,14 +60,7 @@ class WebBrowser(Application):
|
||||
state["last_response_status_code"] = self.latest_response.status_code if self.latest_response else None
|
||||
|
||||
def reset_component_for_episode(self, episode: int):
|
||||
"""
|
||||
Resets the Application component for a new episode.
|
||||
|
||||
This method ensures the Application is ready for a new episode, including resetting any
|
||||
stateful properties or statistics, and clearing any message queues.
|
||||
"""
|
||||
self.domain_name_ip_address = None
|
||||
self.latest_response = None
|
||||
"""Reset the original state of the SimComponent."""
|
||||
|
||||
def get_webpage(self) -> bool:
|
||||
"""
|
||||
|
||||
@@ -34,9 +34,12 @@ class PacketCapture:
|
||||
"The IP address associated with the PCAP logs."
|
||||
self.switch_port_number = switch_port_number
|
||||
"The SwitchPort number."
|
||||
self._setup_logger()
|
||||
|
||||
def _setup_logger(self):
|
||||
self.current_episode: int = 1
|
||||
|
||||
self.setup_logger()
|
||||
|
||||
def setup_logger(self):
|
||||
"""Set up the logger configuration."""
|
||||
log_path = self._get_log_path()
|
||||
|
||||
@@ -75,7 +78,7 @@ class PacketCapture:
|
||||
|
||||
def _get_log_path(self) -> Path:
|
||||
"""Get the path for the log file."""
|
||||
root = SIM_OUTPUT.path / self.hostname
|
||||
root = SIM_OUTPUT.path / f"episode_{self.current_episode}" / self.hostname
|
||||
root.mkdir(exist_ok=True, parents=True)
|
||||
return root / f"{self._logger_name}.log"
|
||||
|
||||
|
||||
@@ -93,6 +93,11 @@ class SessionManager:
|
||||
"""
|
||||
pass
|
||||
|
||||
def clear(self):
|
||||
"""Clears the sessions."""
|
||||
self.sessions_by_key.clear()
|
||||
self.sessions_by_uuid.clear()
|
||||
|
||||
@staticmethod
|
||||
def _get_session_key(
|
||||
frame: Frame, inbound_frame: bool = True
|
||||
|
||||
@@ -31,9 +31,10 @@ class SysLog:
|
||||
:param hostname: The hostname associated with the system logs being recorded.
|
||||
"""
|
||||
self.hostname = hostname
|
||||
self._setup_logger()
|
||||
self.current_episode: int = 1
|
||||
self.setup_logger()
|
||||
|
||||
def _setup_logger(self):
|
||||
def setup_logger(self):
|
||||
"""
|
||||
Configures the logger for this SysLog instance.
|
||||
|
||||
@@ -80,7 +81,7 @@ class SysLog:
|
||||
|
||||
:return: Path object representing the location of the log file.
|
||||
"""
|
||||
root = SIM_OUTPUT.path / self.hostname
|
||||
root = SIM_OUTPUT.path / f"episode_{self.current_episode}" / self.hostname
|
||||
root.mkdir(exist_ok=True, parents=True)
|
||||
return root / f"{self.hostname}_sys.log"
|
||||
|
||||
|
||||
@@ -24,6 +24,12 @@ class Process(Software):
|
||||
operating_state: ProcessOperatingState
|
||||
"The current operating state of the Process."
|
||||
|
||||
def set_original_state(self):
|
||||
"""Sets the original state."""
|
||||
super().set_original_state()
|
||||
vals_to_include = {"operating_state"}
|
||||
self._original_state.update(self.model_dump(include=vals_to_include))
|
||||
|
||||
@abstractmethod
|
||||
def describe_state(self) -> Dict:
|
||||
"""
|
||||
|
||||
@@ -38,6 +38,23 @@ class DatabaseService(Service):
|
||||
self._db_file: File
|
||||
self._create_db_file()
|
||||
|
||||
def set_original_state(self):
|
||||
"""Sets the original state."""
|
||||
super().set_original_state()
|
||||
vals_to_include = {
|
||||
"password",
|
||||
"connections",
|
||||
"backup_server",
|
||||
"latest_backup_directory",
|
||||
"latest_backup_file_name",
|
||||
}
|
||||
self._original_state.update(self.model_dump(include=vals_to_include))
|
||||
|
||||
def reset_component_for_episode(self, episode: int):
|
||||
"""Reset the original state of the SimComponent."""
|
||||
self.connections.clear()
|
||||
super().reset_component_for_episode(episode)
|
||||
|
||||
def configure_backup(self, backup_server: IPv4Address):
|
||||
"""
|
||||
Set up the database backup.
|
||||
|
||||
@@ -29,6 +29,17 @@ class DNSClient(Service):
|
||||
super().__init__(**kwargs)
|
||||
self.start()
|
||||
|
||||
def set_original_state(self):
|
||||
"""Sets the original state."""
|
||||
super().set_original_state()
|
||||
vals_to_include = {"dns_server"}
|
||||
self._original_state.update(self.model_dump(include=vals_to_include))
|
||||
|
||||
def reset_component_for_episode(self, episode: int):
|
||||
"""Reset the original state of the SimComponent."""
|
||||
self.dns_cache.clear()
|
||||
super().reset_component_for_episode(episode)
|
||||
|
||||
def describe_state(self) -> Dict:
|
||||
"""
|
||||
Describes the current state of the software.
|
||||
@@ -42,15 +53,6 @@ class DNSClient(Service):
|
||||
state = super().describe_state()
|
||||
return state
|
||||
|
||||
def reset_component_for_episode(self, episode: int):
|
||||
"""
|
||||
Resets the Service component for a new episode.
|
||||
|
||||
This method ensures the Service is ready for a new episode, including resetting any
|
||||
stateful properties or statistics, and clearing any message queues.
|
||||
"""
|
||||
pass
|
||||
|
||||
def add_domain_to_cache(self, domain_name: str, ip_address: IPv4Address):
|
||||
"""
|
||||
Adds a domain name to the DNS Client cache.
|
||||
|
||||
@@ -28,6 +28,11 @@ class DNSServer(Service):
|
||||
super().__init__(**kwargs)
|
||||
self.start()
|
||||
|
||||
def reset_component_for_episode(self, episode: int):
|
||||
"""Reset the original state of the SimComponent."""
|
||||
self.dns_table.clear()
|
||||
super().reset_component_for_episode(episode)
|
||||
|
||||
def describe_state(self) -> Dict:
|
||||
"""
|
||||
Describes the current state of the software.
|
||||
@@ -62,15 +67,6 @@ class DNSServer(Service):
|
||||
"""
|
||||
self.dns_table[domain_name] = domain_ip_address
|
||||
|
||||
def reset_component_for_episode(self, episode: int):
|
||||
"""
|
||||
Resets the Service component for a new episode.
|
||||
|
||||
This method ensures the Service is ready for a new episode, including resetting any
|
||||
stateful properties or statistics, and clearing any message queues.
|
||||
"""
|
||||
pass
|
||||
|
||||
def receive(
|
||||
self,
|
||||
payload: Any,
|
||||
|
||||
@@ -46,6 +46,12 @@ class Service(IOSoftware):
|
||||
self.health_state_visible = SoftwareHealthState.UNUSED
|
||||
self.health_state_actual = SoftwareHealthState.UNUSED
|
||||
|
||||
def set_original_state(self):
|
||||
"""Sets the original state."""
|
||||
super().set_original_state()
|
||||
vals_to_include = {"operating_state", "restart_duration", "restart_countdown"}
|
||||
self._original_state.update(self.model_dump(include=vals_to_include))
|
||||
|
||||
def _init_request_manager(self) -> RequestManager:
|
||||
rm = super()._init_request_manager()
|
||||
rm.add_request("scan", RequestType(func=lambda request, context: self.scan()))
|
||||
@@ -73,15 +79,6 @@ class Service(IOSoftware):
|
||||
state["health_state_visible"] = self.health_state_visible
|
||||
return state
|
||||
|
||||
def reset_component_for_episode(self, episode: int):
|
||||
"""
|
||||
Resets the Service component for a new episode.
|
||||
|
||||
This method ensures the Service is ready for a new episode, including resetting any
|
||||
stateful properties or statistics, and clearing any message queues.
|
||||
"""
|
||||
pass
|
||||
|
||||
def stop(self) -> None:
|
||||
"""Stop the service."""
|
||||
if self.operating_state in [ServiceOperatingState.RUNNING, ServiceOperatingState.PAUSED]:
|
||||
|
||||
@@ -19,8 +19,14 @@ class WebServer(Service):
|
||||
|
||||
_last_response_status_code: Optional[HttpStatusCode] = None
|
||||
|
||||
def reset_component_for_episode(self, episode: int):
|
||||
"""Reset the original state of the SimComponent."""
|
||||
self._last_response_status_code = None
|
||||
super().reset_component_for_episode(episode)
|
||||
|
||||
@property
|
||||
def last_response_status_code(self) -> HttpStatusCode:
|
||||
"""The latest http response code."""
|
||||
return self._last_response_status_code
|
||||
|
||||
@last_response_status_code.setter
|
||||
@@ -41,14 +47,6 @@ class WebServer(Service):
|
||||
state["last_response_status_code"] = (
|
||||
self.last_response_status_code.value if isinstance(self.last_response_status_code, HttpStatusCode) else None
|
||||
)
|
||||
|
||||
print(
|
||||
f""
|
||||
f"Printing state from Webserver describe func: "
|
||||
f"val={state['last_response_status_code']}, "
|
||||
f"type={type(state['last_response_status_code'])}, "
|
||||
f"Service obj ID={id(self)}"
|
||||
)
|
||||
return state
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
@@ -102,13 +100,6 @@ class WebServer(Service):
|
||||
# return true if response is OK
|
||||
self.last_response_status_code = response.status_code
|
||||
|
||||
print(
|
||||
f""
|
||||
f"Printing state from Webserver http request func: "
|
||||
f"val={self.last_response_status_code}, "
|
||||
f"type={type(self.last_response_status_code)}, "
|
||||
f"Service obj ID={id(self)}"
|
||||
)
|
||||
return response.status_code == HttpStatusCode.OK
|
||||
|
||||
def _handle_get_request(self, payload: HttpRequestPacket) -> HttpResponsePacket:
|
||||
|
||||
@@ -89,6 +89,19 @@ class Software(SimComponent):
|
||||
folder: Optional[Folder] = None
|
||||
"The folder on the file system the Software uses."
|
||||
|
||||
def set_original_state(self):
|
||||
"""Sets the original state."""
|
||||
vals_to_include = {
|
||||
"name",
|
||||
"health_state_actual",
|
||||
"health_state_visible",
|
||||
"criticality",
|
||||
"patching_count",
|
||||
"scanning_count",
|
||||
"revealed_to_red",
|
||||
}
|
||||
self._original_state = self.model_dump(include=vals_to_include)
|
||||
|
||||
def _init_request_manager(self) -> RequestManager:
|
||||
rm = super()._init_request_manager()
|
||||
rm.add_request(
|
||||
@@ -131,16 +144,6 @@ class Software(SimComponent):
|
||||
)
|
||||
return state
|
||||
|
||||
def reset_component_for_episode(self, episode: int):
|
||||
"""
|
||||
Resets the software component for a new episode.
|
||||
|
||||
This method should ensure the software is ready for a new episode, including resetting any
|
||||
stateful properties or statistics, and clearing any message queues. The specifics of what constitutes a
|
||||
"reset" should be implemented in subclasses.
|
||||
"""
|
||||
pass
|
||||
|
||||
def set_health_state(self, health_state: SoftwareHealthState) -> None:
|
||||
"""
|
||||
Assign a new health state to this software.
|
||||
@@ -203,6 +206,12 @@ class IOSoftware(Software):
|
||||
port: Port
|
||||
"The port to which the software is connected."
|
||||
|
||||
def set_original_state(self):
|
||||
"""Sets the original state."""
|
||||
super().set_original_state()
|
||||
vals_to_include = {"installing_count", "max_sessions", "tcp", "udp", "port"}
|
||||
self._original_state.update(self.model_dump(include=vals_to_include))
|
||||
|
||||
@abstractmethod
|
||||
def describe_state(self) -> Dict:
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user