#2900 - Changes to terminal to include a last_response attribute, for use in obtaining RequestResponse from remote command executions

This commit is contained in:
Charlie Crane
2024-09-30 17:38:24 +01:00
parent 33c020e671
commit ac921749a7
2 changed files with 39 additions and 10 deletions

View File

@@ -1711,7 +1711,7 @@ class Node(SimComponent):
""" """
application_name = request[0] application_name = request[0]
if self.software_manager.software.get(application_name): if self.software_manager.software.get(application_name):
self.sys_log.warning(f"Can't install {application_name}. It's already installed.") self.sys_log.info(f"Can't install {application_name}. It's already installed.")
return RequestResponse(status="success", data={"reason": "already installed"}) return RequestResponse(status="success", data={"reason": "already installed"})
application_class = Application._application_registry[application_name] application_class = Application._application_registry[application_name]
self.software_manager.install(application_class) self.software_manager.install(application_class)

View File

@@ -135,12 +135,20 @@ class Terminal(Service):
_client_connection_requests: Dict[str, Optional[Union[str, TerminalClientConnection]]] = {} _client_connection_requests: Dict[str, Optional[Union[str, TerminalClientConnection]]] = {}
"""Dictionary of connect requests made to remote nodes.""" """Dictionary of connect requests made to remote nodes."""
_last_response: Optional[RequestResponse] = None
"""Last response received from RequestManager, for returning remote RequestResponse."""
def __init__(self, **kwargs): def __init__(self, **kwargs):
kwargs["name"] = "Terminal" kwargs["name"] = "Terminal"
kwargs["port"] = Port.SSH kwargs["port"] = Port.SSH
kwargs["protocol"] = IPProtocol.TCP kwargs["protocol"] = IPProtocol.TCP
super().__init__(**kwargs) super().__init__(**kwargs)
@property
def last_response(self) -> Optional[RequestResponse]:
"""Public version of _last_response attribute."""
return self._last_response
def describe_state(self) -> Dict: def describe_state(self) -> Dict:
""" """
Produce a dictionary describing the current state of this object. Produce a dictionary describing the current state of this object.
@@ -202,12 +210,8 @@ class Terminal(Service):
command: str = request[1]["command"] command: str = request[1]["command"]
remote_connection = self._get_connection_from_ip(ip_address=ip_address) remote_connection = self._get_connection_from_ip(ip_address=ip_address)
if remote_connection: if remote_connection:
outcome = remote_connection.execute(command) remote_connection.execute(command)
if outcome: return self.last_response if not None else RequestResponse(status="failure", data={})
return RequestResponse(
status="success",
data={},
)
return RequestResponse( return RequestResponse(
status="failure", status="failure",
data={}, data={},
@@ -243,7 +247,8 @@ class Terminal(Service):
def execute(self, command: List[Any]) -> Optional[RequestResponse]: def execute(self, command: List[Any]) -> Optional[RequestResponse]:
"""Execute a passed ssh command via the request manager.""" """Execute a passed ssh command via the request manager."""
return self.parent.apply_request(command) self._last_response = self.parent.apply_request(command)
return self._last_response
def _get_connection_from_ip(self, ip_address: IPv4Address) -> Optional[RemoteTerminalConnection]: def _get_connection_from_ip(self, ip_address: IPv4Address) -> Optional[RemoteTerminalConnection]:
"""Find Remote Terminal Connection from a given IP.""" """Find Remote Terminal Connection from a given IP."""
@@ -423,10 +428,11 @@ class Terminal(Service):
""" """
source_ip = kwargs["frame"].ip.src_ip_address source_ip = kwargs["frame"].ip.src_ip_address
self.sys_log.info(f"{self.name}: Received payload: {payload}. Source: {source_ip}") self.sys_log.info(f"{self.name}: Received payload: {payload}. Source: {source_ip}")
self._last_response = None # Clear last response
if isinstance(payload, SSHPacket): if isinstance(payload, SSHPacket):
if payload.transport_message == SSHTransportMessage.SSH_MSG_USERAUTH_REQUEST: if payload.transport_message == SSHTransportMessage.SSH_MSG_USERAUTH_REQUEST:
# validate & add connection # validate & add connection
# TODO: uncomment this as part of 2781
username = payload.user_account.username username = payload.user_account.username
password = payload.user_account.password password = payload.user_account.password
connection_id = self.parent.user_session_manager.remote_login( connection_id = self.parent.user_session_manager.remote_login(
@@ -472,6 +478,9 @@ class Terminal(Service):
session_id=session_id, session_id=session_id,
source_ip=source_ip, source_ip=source_ip,
) )
self._last_response: RequestResponse = RequestResponse(
status="success", data={"reason": "Login Successful"}
)
elif payload.transport_message == SSHTransportMessage.SSH_MSG_SERVICE_REQUEST: elif payload.transport_message == SSHTransportMessage.SSH_MSG_SERVICE_REQUEST:
# Requesting a command to be executed # Requesting a command to be executed
@@ -483,12 +492,32 @@ class Terminal(Service):
payload.connection_uuid payload.connection_uuid
) )
remote_session.last_active_step = self.software_manager.node.user_session_manager.current_timestep remote_session.last_active_step = self.software_manager.node.user_session_manager.current_timestep
self.execute(command) self._last_response: RequestResponse = self.execute(command)
if self._last_response.status == "success":
transport_message = SSHTransportMessage.SSH_MSG_SERVICE_SUCCESS
else:
transport_message = SSHTransportMessage.SSH_MSG_SERVICE_FAILED
payload: SSHPacket = SSHPacket(
payload=self._last_response,
transport_message=transport_message,
connection_message=SSHConnectionMessage.SSH_MSG_CHANNEL_DATA,
)
self.software_manager.send_payload_to_session_manager(
payload=payload, dest_port=self.port, session_id=session_id
)
return True return True
else: else:
self.sys_log.error( self.sys_log.error(
f"{self.name}: Connection UUID:{payload.connection_uuid} is not valid. Rejecting Command." f"{self.name}: Connection UUID:{payload.connection_uuid} is not valid. Rejecting Command."
) )
elif (
payload.transport_message == SSHTransportMessage.SSH_MSG_SERVICE_SUCCESS
or SSHTransportMessage.SSH_MSG_SERVICE_FAILED
):
# Likely receiving command ack from remote.
self._last_response = payload.payload
if isinstance(payload, dict) and payload.get("type"): if isinstance(payload, dict) and payload.get("type"):
if payload["type"] == "disconnect": if payload["type"] == "disconnect":