From: Luca Vizzarro <luca.vizzarro@arm.com>
To: dev@dpdk.org
Cc: Luca Vizzarro <luca.vizzarro@arm.com>,
Paul Szczepanek <paul.szczepanek@arm.com>,
Patrick Robb <probb@iol.unh.edu>
Subject: [PATCH v2 7/7] dts: enable shell pooling
Date: Fri, 14 Mar 2025 15:18:57 +0200 [thread overview]
Message-ID: <20250314131857.1298247-8-luca.vizzarro@arm.com> (raw)
In-Reply-To: <20250314131857.1298247-1-luca.vizzarro@arm.com>
Enable the ShellPool class to be used in the test run, and let
InteractiveShells register themselves to the pool upon shell startup.
Moreover, to avoid the ShellPool to call InteractiveShell.close more
than once if the shell was not unregistered correctly, add a way to
prevent the method to be called if the shell has already been closed.
Signed-off-by: Luca Vizzarro <luca.vizzarro@arm.com>
Reviewed-by: Paul Szczepanek <paul.szczepanek@arm.com>
---
.../remote_session/interactive_shell.py | 24 ++++++++++++++++++-
dts/framework/remote_session/python_shell.py | 3 ++-
dts/framework/remote_session/testpmd_shell.py | 2 ++
dts/framework/test_run.py | 5 ++++
4 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/dts/framework/remote_session/interactive_shell.py b/dts/framework/remote_session/interactive_shell.py
index d7e566e5c4..ba8489eafa 100644
--- a/dts/framework/remote_session/interactive_shell.py
+++ b/dts/framework/remote_session/interactive_shell.py
@@ -22,12 +22,14 @@
"""
from abc import ABC, abstractmethod
+from collections.abc import Callable
from pathlib import PurePath
-from typing import ClassVar
+from typing import ClassVar, Concatenate, ParamSpec, TypeAlias, TypeVar
from paramiko import Channel, channel
from typing_extensions import Self
+from framework.context import get_ctx
from framework.exception import (
InteractiveCommandExecutionError,
InteractiveSSHSessionDeadError,
@@ -38,6 +40,23 @@
from framework.settings import SETTINGS
from framework.testbed_model.node import Node
+P = ParamSpec("P")
+T = TypeVar("T", bound="InteractiveShell")
+R = TypeVar("R")
+InteractiveShellMethod = Callable[Concatenate[T, P], R]
+InteractiveShellDecorator: TypeAlias = Callable[[InteractiveShellMethod], InteractiveShellMethod]
+
+
+def only_active(func: InteractiveShellMethod) -> InteractiveShellMethod:
+ """This decorator will skip running the method if the SSH channel is not active."""
+
+ def _wrapper(self: "InteractiveShell", *args: P.args, **kwargs: P.kwargs) -> R | None:
+ if self._ssh_channel.active:
+ return func(self, *args, **kwargs)
+ return None
+
+ return _wrapper
+
class InteractiveShell(ABC):
"""The base class for managing interactive shells.
@@ -155,6 +174,7 @@ def start_application(self, prompt: str | None = None) -> None:
self.is_alive = False # update state on failure to start
raise InteractiveCommandExecutionError("Failed to start application.")
self._ssh_channel.settimeout(self._timeout)
+ get_ctx().shell_pool.register_shell(self)
def send_command(
self, command: str, prompt: str | None = None, skip_first_line: bool = False
@@ -219,6 +239,7 @@ def send_command(
self._logger.debug(f"Got output: {out}")
return out
+ @only_active
def close(self) -> None:
"""Close the shell.
@@ -234,6 +255,7 @@ def close(self) -> None:
self._logger.debug("Application failed to exit before set timeout.")
raise InteractiveSSHTimeoutError("Application 'exit' command") from e
self._ssh_channel.close()
+ get_ctx().shell_pool.unregister_shell(self)
@property
@abstractmethod
diff --git a/dts/framework/remote_session/python_shell.py b/dts/framework/remote_session/python_shell.py
index 6331d047c4..5b380a5c7a 100644
--- a/dts/framework/remote_session/python_shell.py
+++ b/dts/framework/remote_session/python_shell.py
@@ -15,7 +15,7 @@
from pathlib import PurePath
from typing import ClassVar
-from .interactive_shell import InteractiveShell
+from .interactive_shell import InteractiveShell, only_active
class PythonShell(InteractiveShell):
@@ -32,6 +32,7 @@ def path(self) -> PurePath:
"""Path to the Python3 executable."""
return PurePath("python3")
+ @only_active
def close(self):
"""Close Python shell."""
return super().close()
diff --git a/dts/framework/remote_session/testpmd_shell.py b/dts/framework/remote_session/testpmd_shell.py
index 19437b6233..b1939e4a51 100644
--- a/dts/framework/remote_session/testpmd_shell.py
+++ b/dts/framework/remote_session/testpmd_shell.py
@@ -33,6 +33,7 @@
)
from framework.context import get_ctx
+from framework.remote_session.interactive_shell import only_active
from framework.testbed_model.topology import TopologyType
if TYPE_CHECKING or environ.get("DTS_DOC_BUILD"):
@@ -2314,6 +2315,7 @@ def rx_vxlan(self, vxlan_id: int, port_id: int, enable: bool, verify: bool = Tru
self._logger.debug(f"Failed to set VXLAN:\n{vxlan_output}")
raise InteractiveCommandExecutionError(f"Failed to set VXLAN:\n{vxlan_output}")
+ @only_active
def close(self) -> None:
"""Overrides :meth:`~.interactive_shell.close`."""
self.stop()
diff --git a/dts/framework/test_run.py b/dts/framework/test_run.py
index f9cfe5e908..7708fe31bd 100644
--- a/dts/framework/test_run.py
+++ b/dts/framework/test_run.py
@@ -430,6 +430,7 @@ def description(self) -> str:
def next(self) -> State | None:
"""Next state."""
+ self.test_run.ctx.shell_pool.terminate_current_pool()
self.test_run.ctx.tg.teardown(self.test_run.ctx.topology.tg_ports)
self.test_run.ctx.dpdk.teardown(self.test_run.ctx.topology.sut_ports)
self.test_run.ctx.tg_node.teardown()
@@ -473,6 +474,7 @@ def description(self) -> str:
def next(self) -> State | None:
"""Next state."""
+ self.test_run.ctx.shell_pool.start_new_pool()
self.test_suite.set_up_suite()
self.result.update_setup(Result.PASS)
return TestSuiteExecution(self.test_run, self.test_suite, self.result)
@@ -544,6 +546,7 @@ def next(self) -> State | None:
"""Next state."""
self.test_suite.tear_down_suite()
self.test_run.ctx.dpdk.kill_cleanup_dpdk_apps()
+ self.test_run.ctx.shell_pool.terminate_current_pool()
self.result.update_teardown(Result.PASS)
return TestRunExecution(self.test_run, self.test_run.result)
@@ -594,6 +597,7 @@ def description(self) -> str:
def next(self) -> State | None:
"""Next state."""
+ self.test_run.ctx.shell_pool.start_new_pool()
self.test_suite.set_up_test_case()
self.result.update_setup(Result.PASS)
return TestCaseExecution(
@@ -670,6 +674,7 @@ def description(self) -> str:
def next(self) -> State | None:
"""Next state."""
self.test_suite.tear_down_test_case()
+ self.test_run.ctx.shell_pool.terminate_current_pool()
self.result.update_teardown(Result.PASS)
return TestSuiteExecution(self.test_run, self.test_suite, self.test_suite_result)
--
2.43.0
prev parent reply other threads:[~2025-03-14 13:20 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-12-20 17:23 [RFC PATCH 0/2] dts: add basic scope to improve shell handling Luca Vizzarro
2024-12-20 17:24 ` [RFC PATCH 1/2] dts: add scoping and shell registration to Node Luca Vizzarro
2024-12-20 17:24 ` [RFC PATCH 2/2] dts: revert back shell split Luca Vizzarro
2025-03-14 13:18 ` [PATCH v2 0/7] dts: shell improvements Luca Vizzarro
2025-03-14 13:18 ` [PATCH v2 1/7] dts: escape single quotes Luca Vizzarro
2025-03-14 13:18 ` [PATCH v2 2/7] dts: add blocking dpdk app class Luca Vizzarro
2025-03-14 13:18 ` [PATCH v2 3/7] dts: add shells pool Luca Vizzarro
2025-03-14 13:18 ` [PATCH v2 4/7] dts: revert back to a single InteractiveShell Luca Vizzarro
2025-03-14 13:18 ` [PATCH v2 5/7] dts: make shells path dynamic Luca Vizzarro
2025-03-14 13:18 ` [PATCH v2 6/7] dts: remove multi-inheritance classes Luca Vizzarro
2025-03-14 13:18 ` Luca Vizzarro [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250314131857.1298247-8-luca.vizzarro@arm.com \
--to=luca.vizzarro@arm.com \
--cc=dev@dpdk.org \
--cc=paul.szczepanek@arm.com \
--cc=probb@iol.unh.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).