From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 50486A00C2; Mon, 26 Sep 2022 16:17:58 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 7FF5142B7E; Mon, 26 Sep 2022 16:17:27 +0200 (CEST) Received: from lb.pantheon.sk (lb.pantheon.sk [46.229.239.20]) by mails.dpdk.org (Postfix) with ESMTP id 13C61427F5 for ; Mon, 26 Sep 2022 16:17:24 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by lb.pantheon.sk (Postfix) with ESMTP id 4C3E3243CCC; Mon, 26 Sep 2022 16:17:23 +0200 (CEST) X-Virus-Scanned: amavisd-new at siecit.sk Received: from lb.pantheon.sk ([127.0.0.1]) by localhost (lb.pantheon.sk [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id nWQeW4kUmfTf; Mon, 26 Sep 2022 16:17:22 +0200 (CEST) Received: from entguard.lab.pantheon.local (unknown [46.229.239.141]) by lb.pantheon.sk (Postfix) with ESMTP id CD825243CF7; Mon, 26 Sep 2022 16:17:16 +0200 (CEST) From: =?UTF-8?q?Juraj=20Linke=C5=A1?= To: thomas@monjalon.net, david.marchand@redhat.com, Honnappa.Nagarahalli@arm.com, ohilyard@iol.unh.edu, lijuan.tu@intel.com, kda@semihalf.com, bruce.richardson@intel.com Cc: dev@dpdk.org, =?UTF-8?q?Juraj=20Linke=C5=A1?= Subject: [PATCH v5 05/10] dts: add remote session abstraction Date: Mon, 26 Sep 2022 14:17:08 +0000 Message-Id: <20220926141713.2415010-6-juraj.linkes@pantheon.tech> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220926141713.2415010-1-juraj.linkes@pantheon.tech> References: <20220926141713.2415010-1-juraj.linkes@pantheon.tech> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org The abstraction allows for easy switching of implementations of remote connections (ssh, telnet, etc.). It implements some common features, such as logging of commands and their outputs and history bookkeeping and defines methods that must be implemented by derived classes. Signed-off-by: Owen Hilyard Signed-off-by: Juraj Linkeš --- dts/framework/remote_session/__init__.py | 5 + .../remote_session/remote_session.py | 100 ++++++++++++++++++ dts/framework/settings.py | 12 +++ 3 files changed, 117 insertions(+) create mode 100644 dts/framework/remote_session/__init__.py create mode 100644 dts/framework/remote_session/remote_session.py diff --git a/dts/framework/remote_session/__init__.py b/dts/framework/remote_session/__init__.py new file mode 100644 index 0000000000..ecf2f5099f --- /dev/null +++ b/dts/framework/remote_session/__init__.py @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2022 PANTHEON.tech s.r.o. +# + +from .session_factory import RemoteSession, create_remote_session diff --git a/dts/framework/remote_session/remote_session.py b/dts/framework/remote_session/remote_session.py new file mode 100644 index 0000000000..8b55c04a95 --- /dev/null +++ b/dts/framework/remote_session/remote_session.py @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2014 Intel Corporation +# Copyright(c) 2022 PANTHEON.tech s.r.o. +# Copyright(c) 2022 University of New Hampshire +# + +import dataclasses +from abc import ABC, abstractmethod +from typing import Optional + +from framework.config import NodeConfiguration +from framework.logger import DTSLOG +from framework.settings import SETTINGS + + +@dataclasses.dataclass(slots=True, frozen=True) +class HistoryRecord: + command: str + name: str + output: str | int + + +class RemoteSession(ABC): + _node_config: NodeConfiguration + hostname: str + username: str + password: str + ip: str + port: Optional[int] + name: str + logger: DTSLOG + history: list[HistoryRecord] + + def __init__( + self, + node_config: NodeConfiguration, + session_name: str, + logger: DTSLOG, + ): + self._node_config = node_config + self.logger = logger + self.name = session_name + + self.hostname = node_config.hostname + self.ip = self.hostname + self.port = None + if ":" in self.hostname: + self.ip, port = self.hostname.split(":") + self.port = int(port) + + self.username = node_config.user + self.password = node_config.password or "" + self.logger.info(f"Remote {self.username}@{self.hostname}") + self.history = [] + + self._connect() + + def _history_add(self, command: str, output: str) -> None: + self.history.append( + HistoryRecord(command=command, name=self.name, output=output) + ) + + def send_command(self, command: str, timeout: float = SETTINGS.timeout) -> str: + self.logger.info(f"Sending: {command}") + out = self._send_command(command, timeout) + self.logger.debug(f"Received from {command}: {out}") + self._history_add(command=command, output=out) + return out + + def close(self, force: bool = False) -> None: + self.logger.logger_exit() + self._close(force) + + @abstractmethod + def _connect(self) -> None: + """ + Create connection to assigned node. + """ + pass + + @abstractmethod + def _send_command(self, command: str, timeout: float) -> str: + """ + Send a command and return the output. + """ + pass + + @abstractmethod + def _close(self, force: bool = False) -> None: + """ + Close the remote session, freeing all used resources. + """ + pass + + @abstractmethod + def is_alive(self) -> bool: + """ + Check whether the session is still responding. + """ + pass diff --git a/dts/framework/settings.py b/dts/framework/settings.py index ed43ba33a0..39be3808ff 100644 --- a/dts/framework/settings.py +++ b/dts/framework/settings.py @@ -58,6 +58,7 @@ def __call__( class _Settings: config_file_path: str verbose: bool + timeout: float def _get_parser() -> argparse.ArgumentParser: @@ -82,6 +83,16 @@ def _get_parser() -> argparse.ArgumentParser: "to the console.", ) + parser.add_argument( + "-t", + "--timeout", + action=_env_arg("DTS_TIMEOUT"), + default=15, + required=False, + help="[DTS_TIMEOUT] The default timeout for all DTS operations except for " + "compiling DPDK.", + ) + return parser @@ -90,6 +101,7 @@ def _get_settings() -> _Settings: return _Settings( config_file_path=parsed_args.config_file, verbose=(parsed_args.verbose == "Y"), + timeout=float(parsed_args.timeout), ) -- 2.30.2