From patchwork Wed Jun 22 12:14:41 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Juraj_Linke=C5=A1?= X-Patchwork-Id: 113246 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 136CBA04FD; Wed, 22 Jun 2022 14:15:08 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 6FCB34281C; Wed, 22 Jun 2022 14:14:56 +0200 (CEST) Received: from lb.pantheon.sk (lb.pantheon.sk [46.229.239.20]) by mails.dpdk.org (Postfix) with ESMTP id 063F640DDB for ; Wed, 22 Jun 2022 14:14:55 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by lb.pantheon.sk (Postfix) with ESMTP id CB4AE86AAF; Wed, 22 Jun 2022 14:14:53 +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 ztH70gwXwrqb; Wed, 22 Jun 2022 14:14:49 +0200 (CEST) Received: from entguard.lab.pantheon.local (unknown [46.229.239.141]) by lb.pantheon.sk (Postfix) with ESMTP id 46C6C31469; Wed, 22 Jun 2022 14:14:49 +0200 (CEST) From: =?utf-8?q?Juraj_Linke=C5=A1?= To: thomas@monjalon.net, david.marchand@redhat.com, jerinjacobk@gmail.com, ronan.randles@intel.com, Honnappa.Nagarahalli@arm.com, ohilyard@iol.unh.edu, lijuan.tu@intel.com Cc: dev@dpdk.org, =?utf-8?q?Juraj_Linke=C5=A1?= Subject: [PATCH v1 1/8] dts: add ssh pexpect library Date: Wed, 22 Jun 2022 12:14:41 +0000 Message-Id: <20220622121448.3304251-2-juraj.linkes@pantheon.tech> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> References: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> MIME-Version: 1.0 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 library uses the pexpect python library and implements connection to a node and two ways to interact with the node: 1. Send a string with specified prompt which will be matched after the string has been sent to the node. 2. Send a command to be executed. No prompt is specified here. Signed-off-by: Juraj Linkeš --- dts/framework/exception.py | 48 +++++++++ dts/framework/ssh_pexpect.py | 185 +++++++++++++++++++++++++++++++++++ dts/framework/utils.py | 11 +++ 3 files changed, 244 insertions(+) create mode 100644 dts/framework/exception.py create mode 100644 dts/framework/ssh_pexpect.py create mode 100644 dts/framework/utils.py diff --git a/dts/framework/exception.py b/dts/framework/exception.py new file mode 100644 index 0000000000..a109dd1fb8 --- /dev/null +++ b/dts/framework/exception.py @@ -0,0 +1,48 @@ +""" +User-defined exceptions used across the framework. +""" + + +class TimeoutException(Exception): + + """ + Command execution timeout. + """ + + def __init__(self, command, output): + self.command = command + self.output = output + + def __str__(self): + msg = "TIMEOUT on %s" % (self.command) + return msg + + def get_output(self): + return self.output + + +class SSHConnectionException(Exception): + + """ + SSH connection error. + """ + + def __init__(self, host): + self.host = host + + def __str__(self): + return "Error trying to connect with %s" % self.host + + +class SSHSessionDeadException(Exception): + + """ + SSH session is not alive. + It can no longer be used. + """ + + def __init__(self, host): + self.host = host + + def __str__(self): + return "SSH session with %s has been dead" % self.host diff --git a/dts/framework/ssh_pexpect.py b/dts/framework/ssh_pexpect.py new file mode 100644 index 0000000000..bccc6fae94 --- /dev/null +++ b/dts/framework/ssh_pexpect.py @@ -0,0 +1,185 @@ +import time + +from pexpect import pxssh + +from .exception import SSHConnectionException, SSHSessionDeadException, TimeoutException +from .utils import GREEN, RED + +""" +Module handles ssh sessions to TG and SUT. +Implements send_expect function to send commands and get output data. +""" + + +class SSHPexpect: + def __init__(self, node, username, password): + self.magic_prompt = "MAGIC PROMPT" + self.logger = None + + self.node = node + self.username = username + self.password = password + + self._connect_host() + + def _connect_host(self): + """ + Create connection to assigned node. + """ + retry_times = 10 + try: + if ":" in self.node: + while retry_times: + self.ip = self.node.split(":")[0] + self.port = int(self.node.split(":")[1]) + self.session = pxssh.pxssh(encoding="utf-8") + try: + self.session.login( + self.ip, + self.username, + self.password, + original_prompt="[$#>]", + port=self.port, + login_timeout=20, + password_regex=r"(?i)(?:password:)|(?:passphrase for key)|(?i)(password for .+:)", + ) + except Exception as e: + print(e) + time.sleep(2) + retry_times -= 1 + print("retry %d times connecting..." % (10 - retry_times)) + else: + break + else: + raise Exception("connect to %s:%s failed" % (self.ip, self.port)) + else: + self.session = pxssh.pxssh(encoding="utf-8") + self.session.login( + self.node, + self.username, + self.password, + original_prompt="[$#>]", + password_regex=r"(?i)(?:password:)|(?:passphrase for key)|(?i)(password for .+:)", + ) + self.send_expect("stty -echo", "#") + self.send_expect("stty columns 1000", "#") + except Exception as e: + print(RED(e)) + if getattr(self, "port", None): + suggestion = ( + "\nSuggession: Check if the firewall on [ %s ] " % self.ip + + "is stopped\n" + ) + print(GREEN(suggestion)) + + raise SSHConnectionException(self.node) + + def init_log(self, logger): + self.logger = logger + self.logger.info("ssh %s@%s" % (self.username, self.node)) + + def send_expect_base(self, command, expected, timeout): + self.clean_session() + self.session.PROMPT = expected + self.__sendline(command) + self.__prompt(command, timeout) + + before = self.get_output_before() + return before + + def send_expect(self, command, expected, timeout=15, verify=False): + + try: + ret = self.send_expect_base(command, expected, timeout) + if verify: + ret_status = self.send_expect_base("echo $?", expected, timeout) + if not int(ret_status): + return ret + else: + self.logger.error("Command: %s failure!" % command) + self.logger.error(ret) + return int(ret_status) + else: + return ret + except Exception as e: + print( + RED( + "Exception happened in [%s] and output is [%s]" + % (command, self.get_output_before()) + ) + ) + raise e + + def send_command(self, command, timeout=1): + try: + self.clean_session() + self.__sendline(command) + except Exception as e: + raise e + + output = self.get_session_before(timeout=timeout) + self.session.PROMPT = self.session.UNIQUE_PROMPT + self.session.prompt(0.1) + + return output + + def clean_session(self): + self.get_session_before(timeout=0.01) + + def get_session_before(self, timeout=15): + """ + Get all output before timeout + """ + self.session.PROMPT = self.magic_prompt + try: + self.session.prompt(timeout) + except Exception as e: + pass + + before = self.get_output_all() + self.__flush() + + return before + + def __flush(self): + """ + Clear all session buffer + """ + self.session.buffer = "" + self.session.before = "" + + def __prompt(self, command, timeout): + if not self.session.prompt(timeout): + raise TimeoutException(command, self.get_output_all()) from None + + def __sendline(self, command): + if not self.isalive(): + raise SSHSessionDeadException(self.node) + if len(command) == 2 and command.startswith("^"): + self.session.sendcontrol(command[1]) + else: + self.session.sendline(command) + + def get_output_before(self): + if not self.isalive(): + raise SSHSessionDeadException(self.node) + before = self.session.before.rsplit("\r\n", 1) + if before[0] == "[PEXPECT]": + before[0] = "" + + return before[0] + + def get_output_all(self): + output = self.session.before + output.replace("[PEXPECT]", "") + return output + + def close(self, force=False): + if force is True: + self.session.close() + else: + if self.isalive(): + self.session.logout() + + def isalive(self): + return self.session.isalive() diff --git a/dts/framework/utils.py b/dts/framework/utils.py new file mode 100644 index 0000000000..0ffd992952 --- /dev/null +++ b/dts/framework/utils.py @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2014 Intel Corporation +# + + +def RED(text): + return "\x1B[" + "31;1m" + str(text) + "\x1B[" + "0m" + + +def GREEN(text): + return "\x1B[" + "32;1m" + str(text) + "\x1B[" + "0m" From patchwork Wed Jun 22 12:14:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Juraj_Linke=C5=A1?= X-Patchwork-Id: 113245 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 685A6A04FD; Wed, 22 Jun 2022 14:15:01 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 6FA714280B; Wed, 22 Jun 2022 14:14:55 +0200 (CEST) Received: from lb.pantheon.sk (lb.pantheon.sk [46.229.239.20]) by mails.dpdk.org (Postfix) with ESMTP id 14BF440DDB for ; Wed, 22 Jun 2022 14:14:54 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by lb.pantheon.sk (Postfix) with ESMTP id BF63C31470; Wed, 22 Jun 2022 14:14:52 +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 tRGSwXA3wpss; Wed, 22 Jun 2022 14:14:51 +0200 (CEST) Received: from entguard.lab.pantheon.local (unknown [46.229.239.141]) by lb.pantheon.sk (Postfix) with ESMTP id C60D83146B; Wed, 22 Jun 2022 14:14:49 +0200 (CEST) From: =?utf-8?q?Juraj_Linke=C5=A1?= To: thomas@monjalon.net, david.marchand@redhat.com, jerinjacobk@gmail.com, ronan.randles@intel.com, Honnappa.Nagarahalli@arm.com, ohilyard@iol.unh.edu, lijuan.tu@intel.com Cc: dev@dpdk.org, =?utf-8?q?Juraj_Linke=C5=A1?= Subject: [PATCH v1 2/8] dts: add locks for parallel node connections Date: Wed, 22 Jun 2022 12:14:42 +0000 Message-Id: <20220622121448.3304251-3-juraj.linkes@pantheon.tech> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> References: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> MIME-Version: 1.0 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 Each lock is held per node. The lock assures that multiple connections to the same node don't execute anything at the same time, removing the possibility of race conditions. Signed-off-by: Juraj Linkeš --- dts/framework/ssh_pexpect.py | 15 +++++-- dts/framework/utils.py | 81 ++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 4 deletions(-) diff --git a/dts/framework/ssh_pexpect.py b/dts/framework/ssh_pexpect.py index bccc6fae94..cbdbb91b64 100644 --- a/dts/framework/ssh_pexpect.py +++ b/dts/framework/ssh_pexpect.py @@ -3,7 +3,7 @@ from pexpect import pxssh from .exception import SSHConnectionException, SSHSessionDeadException, TimeoutException -from .utils import GREEN, RED +from .utils import GREEN, RED, parallel_lock """ Module handles ssh sessions to TG and SUT. @@ -12,7 +12,7 @@ class SSHPexpect: - def __init__(self, node, username, password): + def __init__(self, node, username, password, sut_id): self.magic_prompt = "MAGIC PROMPT" self.logger = None @@ -20,11 +20,18 @@ def __init__(self, node, username, password): self.username = username self.password = password - self._connect_host() + self._connect_host(sut_id=sut_id) - def _connect_host(self): + @parallel_lock(num=8) + def _connect_host(self, sut_id=0): """ Create connection to assigned node. + Parameter sut_id will be used in parallel_lock thus can assure + isolated locks for each node. + Parallel ssh connections are limited to MaxStartups option in SSHD + configuration file. By default concurrent number is 10, so default + threads number is limited to 8 which less than 10. Lock number can + be modified along with MaxStartups value. """ retry_times = 10 try: diff --git a/dts/framework/utils.py b/dts/framework/utils.py index 0ffd992952..a8e739f7b2 100644 --- a/dts/framework/utils.py +++ b/dts/framework/utils.py @@ -2,6 +2,87 @@ # Copyright(c) 2010-2014 Intel Corporation # +import threading +from functools import wraps + + +def parallel_lock(num=1): + """ + Wrapper function for protect parallel threads, allow multiple threads + share one lock. Locks are created based on function name. Thread locks are + separated between SUTs according to argument 'sut_id'. + Parameter: + num: Number of parallel threads for the lock + """ + global locks_info + + def decorate(func): + @wraps(func) + def wrapper(*args, **kwargs): + if "sut_id" in kwargs: + sut_id = kwargs["sut_id"] + else: + sut_id = 0 + + # in case function arguments is not correct + if sut_id >= len(locks_info): + sut_id = 0 + + lock_info = locks_info[sut_id] + uplock = lock_info["update_lock"] + + name = func.__name__ + uplock.acquire() + + if name not in lock_info: + lock_info[name] = dict() + lock_info[name]["lock"] = threading.RLock() + lock_info[name]["current_thread"] = 1 + else: + lock_info[name]["current_thread"] += 1 + + lock = lock_info[name]["lock"] + + # make sure when owned global lock, should also own update lock + if lock_info[name]["current_thread"] >= num: + if lock._is_owned(): + print( + RED( + "SUT%d %s waiting for func lock %s" + % (sut_id, threading.current_thread().name, func.__name__) + ) + ) + lock.acquire() + else: + uplock.release() + + try: + ret = func(*args, **kwargs) + except Exception as e: + if not uplock._is_owned(): + uplock.acquire() + + if lock._is_owned(): + lock.release() + lock_info[name]["current_thread"] = 0 + uplock.release() + raise e + + if not uplock._is_owned(): + uplock.acquire() + + if lock._is_owned(): + lock.release() + lock_info[name]["current_thread"] = 0 + + uplock.release() + + return ret + + return wrapper + + return decorate + def RED(text): return "\x1B[" + "31;1m" + str(text) + "\x1B[" + "0m" From patchwork Wed Jun 22 12:14:43 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Juraj_Linke=C5=A1?= X-Patchwork-Id: 113249 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id EF6B7A04FD; Wed, 22 Jun 2022 14:15:24 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id B386542905; Wed, 22 Jun 2022 14:15:02 +0200 (CEST) Received: from lb.pantheon.sk (lb.pantheon.sk [46.229.239.20]) by mails.dpdk.org (Postfix) with ESMTP id 8B1A1427F3 for ; Wed, 22 Jun 2022 14:14:58 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by lb.pantheon.sk (Postfix) with ESMTP id A406331473; Wed, 22 Jun 2022 14:14:57 +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 ZbgEJmH7LPzK; Wed, 22 Jun 2022 14:14:53 +0200 (CEST) Received: from entguard.lab.pantheon.local (unknown [46.229.239.141]) by lb.pantheon.sk (Postfix) with ESMTP id 508823146C; Wed, 22 Jun 2022 14:14:50 +0200 (CEST) From: =?utf-8?q?Juraj_Linke=C5=A1?= To: thomas@monjalon.net, david.marchand@redhat.com, jerinjacobk@gmail.com, ronan.randles@intel.com, Honnappa.Nagarahalli@arm.com, ohilyard@iol.unh.edu, lijuan.tu@intel.com Cc: dev@dpdk.org, =?utf-8?q?Juraj_Linke=C5=A1?= Subject: [PATCH v1 3/8] dts: add ssh connection extension Date: Wed, 22 Jun 2022 12:14:43 +0000 Message-Id: <20220622121448.3304251-4-juraj.linkes@pantheon.tech> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> References: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> MIME-Version: 1.0 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 class adds logging to existing pexpect methods and history records. Signed-off-by: Juraj Linkeš --- dts/framework/ssh_connection.py | 52 +++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 dts/framework/ssh_connection.py diff --git a/dts/framework/ssh_connection.py b/dts/framework/ssh_connection.py new file mode 100644 index 0000000000..2ddbc9c1c2 --- /dev/null +++ b/dts/framework/ssh_connection.py @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2014 Intel Corporation +# + +from .ssh_pexpect import SSHPexpect + + +class SSHConnection(object): + + """ + Module for create session to node. + """ + + def __init__(self, node, session_name, username, password="", sut_id=0): + self.session = SSHPexpect(node, username, password, sut_id) + self.name = session_name + self.history = None + + def init_log(self, logger): + self.logger = logger + self.session.init_log(logger) + + def set_history(self, history): + self.history = history + + def send_expect(self, cmds, expected, timeout=15, verify=False): + self.logger.info(cmds) + out = self.session.send_expect(cmds, expected, timeout, verify) + if isinstance(out, str): + self.logger.debug(out.replace(cmds, "")) + if type(self.history) is list: + self.history.append({"command": cmds, "name": self.name, "output": out}) + return out + + def send_command(self, cmds, timeout=1): + self.logger.info(cmds) + out = self.session.send_command(cmds, timeout) + self.logger.debug(out.replace(cmds, "")) + if type(self.history) is list: + self.history.append({"command": cmds, "name": self.name, "output": out}) + return out + + def get_session_before(self, timeout=15): + out = self.session.get_session_before(timeout) + self.logger.debug(out) + return out + + def close(self, force=False): + if getattr(self, "logger", None): + self.logger.logger_exit() + + self.session.close(force) From patchwork Wed Jun 22 12:14:44 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Juraj_Linke=C5=A1?= X-Patchwork-Id: 113247 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 39B12A04FD; Wed, 22 Jun 2022 14:15:14 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 6797D4281B; Wed, 22 Jun 2022 14:14:59 +0200 (CEST) Received: from lb.pantheon.sk (lb.pantheon.sk [46.229.239.20]) by mails.dpdk.org (Postfix) with ESMTP id 6F0494281B for ; Wed, 22 Jun 2022 14:14:56 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by lb.pantheon.sk (Postfix) with ESMTP id AF6893146B; Wed, 22 Jun 2022 14:14:55 +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 PJKwmepIb7td; Wed, 22 Jun 2022 14:14:54 +0200 (CEST) Received: from entguard.lab.pantheon.local (unknown [46.229.239.141]) by lb.pantheon.sk (Postfix) with ESMTP id 01C713146E; Wed, 22 Jun 2022 14:14:50 +0200 (CEST) From: =?utf-8?q?Juraj_Linke=C5=A1?= To: thomas@monjalon.net, david.marchand@redhat.com, jerinjacobk@gmail.com, ronan.randles@intel.com, Honnappa.Nagarahalli@arm.com, ohilyard@iol.unh.edu, lijuan.tu@intel.com Cc: dev@dpdk.org, =?utf-8?q?Juraj_Linke=C5=A1?= Subject: [PATCH v1 4/8] dts: add basic logging facility Date: Wed, 22 Jun 2022 12:14:44 +0000 Message-Id: <20220622121448.3304251-5-juraj.linkes@pantheon.tech> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> References: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> MIME-Version: 1.0 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 logging module provides loggers distinguished by two attributes, a custom format and a verbosity switch. Signed-off-by: Juraj Linkeš --- dts/framework/logger.py | 86 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 dts/framework/logger.py diff --git a/dts/framework/logger.py b/dts/framework/logger.py new file mode 100644 index 0000000000..1bda7c58c5 --- /dev/null +++ b/dts/framework/logger.py @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2014 Intel Corporation +# + +import logging + +""" +DTS logger module with several log level. DTS framework and TestSuite log +will saved into different log files. +""" +verbose = False +date_fmt = "%d/%m/%Y %H:%M:%S" +stream_fmt = "%(name)30s: %(message)s" + +# List for saving all using loggers +global Loggers +Loggers = [] + + +def set_verbose(): + global verbose + verbose = True + + +class DTSLOG(logging.LoggerAdapter): + """ + DTS log class for framework and testsuite. + """ + + def __init__(self, logger, node="suite"): + global log_dir + + self.logger = logger + self.logger.setLevel(logging.DEBUG) + + self.node = node + super(DTSLOG, self).__init__(self.logger, dict(node=self.node)) + + self.sh = None + + # add handler to emit to stdout + sh = logging.StreamHandler() + self.__log_handler(sh) + + def __log_handler(self, sh): + """ + Config stream handler and file handler. + """ + sh.setFormatter(logging.Formatter(stream_fmt, date_fmt)) + + sh.setLevel(logging.DEBUG) # file handler default level + global verbose + if verbose is True: + sh.setLevel(logging.DEBUG) + else: + sh.setLevel(logging.INFO) # console handler default level + + self.logger.addHandler(sh) + + if self.sh is not None: + self.logger.removeHandler(self.sh) + + self.sh = sh + + def logger_exit(self): + """ + Remove stream handler and logfile handler. + """ + if self.sh is not None: + self.logger.removeHandler(self.sh) + + +def getLogger(name, node="suite"): + """ + Get logger handler and if there's no handler for specified Node will create one. + """ + global Loggers + # return saved logger + for logger in Loggers: + if logger["name"] == name and logger["node"] == node: + return logger["logger"] + + # return new logger + logger = DTSLOG(logging.getLogger(name), node) + Loggers.append({"logger": logger, "name": name, "node": node}) + return logger From patchwork Wed Jun 22 12:14:45 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Juraj_Linke=C5=A1?= X-Patchwork-Id: 113248 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 9BFEEA04FD; Wed, 22 Jun 2022 14:15:19 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 89F9B4282C; Wed, 22 Jun 2022 14:15:00 +0200 (CEST) Received: from lb.pantheon.sk (lb.pantheon.sk [46.229.239.20]) by mails.dpdk.org (Postfix) with ESMTP id 0D149427F3 for ; Wed, 22 Jun 2022 14:14:58 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by lb.pantheon.sk (Postfix) with ESMTP id 300A83146E; Wed, 22 Jun 2022 14:14:57 +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 CE5djd7xp1Xw; Wed, 22 Jun 2022 14:14:56 +0200 (CEST) Received: from entguard.lab.pantheon.local (unknown [46.229.239.141]) by lb.pantheon.sk (Postfix) with ESMTP id CDADC31466; Wed, 22 Jun 2022 14:14:51 +0200 (CEST) From: =?utf-8?q?Juraj_Linke=C5=A1?= To: thomas@monjalon.net, david.marchand@redhat.com, jerinjacobk@gmail.com, ronan.randles@intel.com, Honnappa.Nagarahalli@arm.com, ohilyard@iol.unh.edu, lijuan.tu@intel.com Cc: dev@dpdk.org, =?utf-8?q?Juraj_Linke=C5=A1?= Subject: [PATCH v1 5/8] dts: add Node base class Date: Wed, 22 Jun 2022 12:14:45 +0000 Message-Id: <20220622121448.3304251-6-juraj.linkes@pantheon.tech> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> References: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> MIME-Version: 1.0 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 base class implements basic node management methods - connect and execute commands. Signed-off-by: Juraj Linkeš --- dts/framework/node.py | 95 +++++++++++++++++++++++++++++++++++++++ dts/framework/settings.py | 8 ++++ 2 files changed, 103 insertions(+) create mode 100644 dts/framework/node.py create mode 100644 dts/framework/settings.py diff --git a/dts/framework/node.py b/dts/framework/node.py new file mode 100644 index 0000000000..ba9e9574bc --- /dev/null +++ b/dts/framework/node.py @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2014 Intel Corporation +# + +from .logger import getLogger +from .settings import TIMEOUT +from .ssh_connection import SSHConnection + +""" +A node is a generic host that DTS connects to and manages. +""" + + +class Node(object): + + """ + Basic module for node management. This module implements methods that + manage a node, such as information gathering (of CPU/PCI/NIC) and + environment setup. + """ + + def __init__(self, node, sut_id=0, name=None): + self.node = node + + self.logger = getLogger(name) + self.session = SSHConnection( + self.get_ip_address(), + name, + self.get_username(), + self.get_password(), + sut_id, + ) + self.session.init_log(self.logger) + + def get_ip_address(self): + """ + Get SUT's ip address. + """ + return self.node["IP"] + + def get_password(self): + """ + Get SUT's login password. + """ + return self.node["pass"] + + def get_username(self): + """ + Get SUT's login username. + """ + return self.node["user"] + + def send_expect( + self, + cmds, + expected, + timeout=TIMEOUT, + verify=False, + trim_whitespace=True, + ): + """ + Send commands to node and return string before expected string. If + there's no expected string found before timeout, TimeoutException will + be raised. + + By default, it will trim the whitespace from the expected string. This + behavior can be turned off via the trim_whitespace argument. + """ + + if trim_whitespace: + expected = expected.strip() + + return self.session.send_expect(cmds, expected, timeout, verify) + + def send_command(self, cmds, timeout=TIMEOUT): + """ + Send commands to node and return string before timeout. + """ + + return self.session.send_command(cmds, timeout) + + def close(self): + """ + Close ssh session of SUT. + """ + if self.session: + self.session.close() + self.session = None + + def node_exit(self): + """ + Recover all resource before node exit + """ + self.close() + self.logger.logger_exit() diff --git a/dts/framework/settings.py b/dts/framework/settings.py new file mode 100644 index 0000000000..d62083969e --- /dev/null +++ b/dts/framework/settings.py @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2021 Intel Corporation +# + +""" +Default session timeout. +""" +TIMEOUT = 15 From patchwork Wed Jun 22 12:14:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Juraj_Linke=C5=A1?= X-Patchwork-Id: 113250 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 4FDDCA04FD; Wed, 22 Jun 2022 14:15:31 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 5ED3542B70; Wed, 22 Jun 2022 14:15:03 +0200 (CEST) Received: from lb.pantheon.sk (lb.pantheon.sk [46.229.239.20]) by mails.dpdk.org (Postfix) with ESMTP id B46C942824 for ; Wed, 22 Jun 2022 14:14:59 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by lb.pantheon.sk (Postfix) with ESMTP id DEB563146C; Wed, 22 Jun 2022 14:14:58 +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 xoLynyyGKIld; Wed, 22 Jun 2022 14:14:57 +0200 (CEST) Received: from entguard.lab.pantheon.local (unknown [46.229.239.141]) by lb.pantheon.sk (Postfix) with ESMTP id 575363146F; Wed, 22 Jun 2022 14:14:52 +0200 (CEST) From: =?utf-8?q?Juraj_Linke=C5=A1?= To: thomas@monjalon.net, david.marchand@redhat.com, jerinjacobk@gmail.com, ronan.randles@intel.com, Honnappa.Nagarahalli@arm.com, ohilyard@iol.unh.edu, lijuan.tu@intel.com Cc: dev@dpdk.org, =?utf-8?q?Juraj_Linke=C5=A1?= Subject: [PATCH v1 6/8] dts: add config parser module Date: Wed, 22 Jun 2022 12:14:46 +0000 Message-Id: <20220622121448.3304251-7-juraj.linkes@pantheon.tech> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> References: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> MIME-Version: 1.0 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 module uses Python's configparser module, which supports an ini-like format with sections. The configuration is split into two parts, one defining the parameters of the test run and the other defining the topology to be used. Signed-off-by: Juraj Linkeš --- dts/conf/topology.cfg | 9 +++++ dts/execution.cfg | 2 + dts/framework/config.py | 81 ++++++++++++++++++++++++++++++++++++++ dts/framework/exception.py | 13 ++++++ dts/framework/settings.py | 34 ++++++++++++++++ 5 files changed, 139 insertions(+) create mode 100644 dts/conf/topology.cfg create mode 100644 dts/execution.cfg create mode 100644 dts/framework/config.py diff --git a/dts/conf/topology.cfg b/dts/conf/topology.cfg new file mode 100644 index 0000000000..f5406cc6b9 --- /dev/null +++ b/dts/conf/topology.cfg @@ -0,0 +1,9 @@ +#Topology Configuration +#[SUT IP] +# sut_ip: SUT ip address +# sut_user: SUT username +# sut_passwd: SUT password +[SUT IP1] +sut_ip=xxx.xxx.xxx.xxx +sut_user=root +sut_passwd= diff --git a/dts/execution.cfg b/dts/execution.cfg new file mode 100644 index 0000000000..ef671aa394 --- /dev/null +++ b/dts/execution.cfg @@ -0,0 +1,2 @@ +[Execution1] +sut= diff --git a/dts/framework/config.py b/dts/framework/config.py new file mode 100644 index 0000000000..765132a2a0 --- /dev/null +++ b/dts/framework/config.py @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2021 Intel Corporation +# + +""" +Generic port and topology nodes configuration file load function +""" +import configparser # config parse module + +from .exception import ConfigParseException +from .settings import CONFIG_ROOT_PATH + +TOPOCONF = "%s/topology.cfg" % CONFIG_ROOT_PATH + + +class UserConf: + def __init__(self, config): + self.conf = configparser.SafeConfigParser() + load_files = self.conf.read(config) + if load_files == []: + self.conf = None + raise ConfigParseException(config) + + def get_sections(self): + if self.conf is None: + return [] + + return self.conf.sections() + + def load_section(self, section): + if self.conf is None: + return None + + items = None + for conf_sect in self.conf.sections(): + if conf_sect == section: + items = self.conf.items(section) + + return items + + +class TopologyConf(UserConf): + TOPO_DEFAULTS = { + "IP": "", + "user": "", + "pass": "", + } + + def __init__(self, topo_conf=TOPOCONF): + self.config_file = topo_conf + self.nodes = [] + try: + self.topo_conf = UserConf(self.config_file) + except ConfigParseException: + self.topo_conf = None + raise ConfigParseException + + def load_topo_config(self): + sections = self.topo_conf.get_sections() + if not sections: + return self.nodes + + for node_name in sections: + node = self.TOPO_DEFAULTS.copy() + node["section"] = node_name + node_conf = self.topo_conf.load_section(node_name) + if not node_conf: + continue + + # convert file configuration to dts node configuration + for key, value in node_conf: + if key == "sut_ip": + node["IP"] = value + elif key == "sut_user": + node["user"] = value + elif key == "sut_passwd": + node["pass"] = value + + self.nodes.append(node) + return self.nodes + diff --git a/dts/framework/exception.py b/dts/framework/exception.py index a109dd1fb8..a094fcce78 100644 --- a/dts/framework/exception.py +++ b/dts/framework/exception.py @@ -46,3 +46,16 @@ def __init__(self, host): def __str__(self): return "SSH session with %s has been dead" % self.host + + +class ConfigParseException(Exception): + + """ + Configuration file parse failure exception. + """ + + def __init__(self, conf_file): + self.config = conf_file + + def __str__(self): + return "Failed to parse config file [%s]" % (self.config) diff --git a/dts/framework/settings.py b/dts/framework/settings.py index d62083969e..c033a77fec 100644 --- a/dts/framework/settings.py +++ b/dts/framework/settings.py @@ -2,7 +2,41 @@ # Copyright(c) 2010-2021 Intel Corporation # +import os +import re + """ Default session timeout. """ TIMEOUT = 15 + +""" +DTS global environment variables +""" +DTS_ENV_PAT = r"DTS_*" +DTS_CFG_FOLDER = "DTS_CFG_FOLDER" + + +def load_global_setting(key): + """ + Load DTS global setting + """ + if re.match(DTS_ENV_PAT, key): + env_key = key + else: + env_key = "DTS_" + key + + if env_key in list(os.environ.keys()): + return os.environ[env_key] + else: + return "" + + +""" +The root path of framework configs. +""" +dts_cfg_folder = load_global_setting(DTS_CFG_FOLDER) +if dts_cfg_folder != "": + CONFIG_ROOT_PATH = dts_cfg_folder +else: + CONFIG_ROOT_PATH = "./conf" From patchwork Wed Jun 22 12:14:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Juraj_Linke=C5=A1?= X-Patchwork-Id: 113251 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 9BC91A04FD; Wed, 22 Jun 2022 14:15:37 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 08F4142B76; Wed, 22 Jun 2022 14:15:04 +0200 (CEST) Received: from lb.pantheon.sk (lb.pantheon.sk [46.229.239.20]) by mails.dpdk.org (Postfix) with ESMTP id 3A61D4282C for ; Wed, 22 Jun 2022 14:15:00 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by lb.pantheon.sk (Postfix) with ESMTP id 61BFB31475; Wed, 22 Jun 2022 14:14:59 +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 y_oClyWmhOA1; Wed, 22 Jun 2022 14:14:58 +0200 (CEST) Received: from entguard.lab.pantheon.local (unknown [46.229.239.141]) by lb.pantheon.sk (Postfix) with ESMTP id D704331471; Wed, 22 Jun 2022 14:14:52 +0200 (CEST) From: =?utf-8?q?Juraj_Linke=C5=A1?= To: thomas@monjalon.net, david.marchand@redhat.com, jerinjacobk@gmail.com, ronan.randles@intel.com, Honnappa.Nagarahalli@arm.com, ohilyard@iol.unh.edu, lijuan.tu@intel.com Cc: dev@dpdk.org, =?utf-8?q?Juraj_Linke=C5=A1?= Subject: [PATCH v1 7/8] dts: add dts runtime workflow module Date: Wed, 22 Jun 2022 12:14:47 +0000 Message-Id: <20220622121448.3304251-8-juraj.linkes@pantheon.tech> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> References: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> MIME-Version: 1.0 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 module is responsilbe for running DTS. It handles the creation of objects and eventually the whole DTS workflow, such as running node setups, test gathering, setup and execution and various cleanups. Signed-off-by: Juraj Linkeš --- dts/framework/dts.py | 128 +++++++++++++++++++++++++++++++++++++++++ dts/framework/utils.py | 36 ++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 dts/framework/dts.py diff --git a/dts/framework/dts.py b/dts/framework/dts.py new file mode 100644 index 0000000000..59eb163e89 --- /dev/null +++ b/dts/framework/dts.py @@ -0,0 +1,128 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2019 Intel Corporation +# + +import atexit # register callback when exit +import configparser # config parse module +import os # operation system module +import sys + +import framework.logger as logger +import framework.settings as settings # dts settings + +from .config import TopologyConf +from .exception import ConfigParseException +from .logger import getLogger +from .node import Node +from .utils import check_dts_python_version, create_parallel_locks + +log_handler = None + + +def dts_parse_config(config, section): + """ + Parse execution file configuration. + """ + sut_nodes = [sut_.strip() for sut_ in config.get(section, "sut").split(",")] + + return sut_nodes + + +def dts_nodes_init(nodeInsts): + """ + Create dts SUT/TG instance and initialize them. + """ + sut_nodes = [] + + sut_id = 0 + for nodeInst in nodeInsts: + sut_node = Node(nodeInst, sut_id) + sut_nodes.append(sut_node) + sut_id += 1 + + return sut_nodes + + +def dts_nodes_exit(sut_nodes): + """ + Call SUT and TG exit function after execution finished + """ + for sut_node in sut_nodes: + sut_node.node_exit() + + +def run_all( + config_file, + verbose, +): + """ + Main process of DTS, it will run all test suites in the config file. + """ + + global log_handler + + # check the python version of the server that run dts + check_dts_python_version() + + # init log_handler handler + if verbose is True: + logger.set_verbose() + + log_handler = getLogger("dts") + + # Read config file + dts_cfg_folder = settings.load_global_setting(settings.DTS_CFG_FOLDER) + if dts_cfg_folder != "": + config_file = dts_cfg_folder + os.sep + config_file + + config = configparser.SafeConfigParser() + load_cfg = config.read(config_file) + if len(load_cfg) == 0: + raise ConfigParseException(config_file) + + topo_conf = TopologyConf() + nodes = topo_conf.load_topo_config() + + # for all Execution sections + for section in config.sections(): + nodeInsts = list() + + # verify if the delimiter is good if the lists are vertical + sut_nodes = dts_parse_config(config, section) + for sut in sut_nodes: + log_handler.info("\nSUT " + sut) + + # look up in nodes - to find the matching IP + for sut in sut_nodes: + for node in nodes: + if node["section"] == sut: + nodeInsts.append(node) + break + + # only run on the SUT in known nodes + if len(nodeInsts) == 0: + log_handler.error(" SKIP UNKNOWN NODE") + continue + + # init global lock + create_parallel_locks(len(sut_nodes)) + + # init SUT, TG node + sut_nodes = dts_nodes_init(nodeInsts) + # register exit action + atexit.register(quit_execution, sut_nodes) + + dts_nodes_exit(sut_nodes) + + +def quit_execution(sut_nodes): + """ + Close session to SUT and TG before quit. + Return exit status when failure occurred. + """ + for sut_node in sut_nodes: + # close all session + sut_node.node_exit() + + log_handler.info("DTS ended") + sys.exit(0) diff --git a/dts/framework/utils.py b/dts/framework/utils.py index a8e739f7b2..0800aa8158 100644 --- a/dts/framework/utils.py +++ b/dts/framework/utils.py @@ -2,10 +2,23 @@ # Copyright(c) 2010-2014 Intel Corporation # +import sys import threading from functools import wraps +def create_parallel_locks(num_suts): + """ + Create thread lock dictionary based on SUTs number + """ + global locks_info + locks_info = [] + for _ in range(num_suts): + lock_info = dict() + lock_info["update_lock"] = threading.RLock() + locks_info.append(lock_info) + + def parallel_lock(num=1): """ Wrapper function for protect parallel threads, allow multiple threads @@ -90,3 +103,26 @@ def RED(text): def GREEN(text): return "\x1B[" + "32;1m" + str(text) + "\x1B[" + "0m" + + +def check_dts_python_version(): + if ( + sys.version_info.major < 3 + or (sys.version_info.major == 3 and sys.version_info.minor < 6) + or ( + sys.version_info.major == 3 + and sys.version_info.minor == 6 + and sys.version_info.micro < 9 + ) + ): + print( + RED( + ( + "WARNING: Dts running node python version is lower than python 3.6, " + "it is deprecated for use in DTS, " + "and will not work in future releases." + ) + ), + file=sys.stderr, + ) + print(RED("Please use Python >= 3.6.9 instead"), file=sys.stderr) From patchwork Wed Jun 22 12:14:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Juraj_Linke=C5=A1?= X-Patchwork-Id: 113252 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 0976DA04FD; Wed, 22 Jun 2022 14:15:43 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id B295A42B7C; Wed, 22 Jun 2022 14:15:04 +0200 (CEST) Received: from lb.pantheon.sk (lb.pantheon.sk [46.229.239.20]) by mails.dpdk.org (Postfix) with ESMTP id 22F7142905 for ; Wed, 22 Jun 2022 14:15:01 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by lb.pantheon.sk (Postfix) with ESMTP id 5AD5B3146F; Wed, 22 Jun 2022 14:15:00 +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 dFMbU427vPka; Wed, 22 Jun 2022 14:14:59 +0200 (CEST) Received: from entguard.lab.pantheon.local (unknown [46.229.239.141]) by lb.pantheon.sk (Postfix) with ESMTP id AC7D831472; Wed, 22 Jun 2022 14:14:53 +0200 (CEST) From: =?utf-8?q?Juraj_Linke=C5=A1?= To: thomas@monjalon.net, david.marchand@redhat.com, jerinjacobk@gmail.com, ronan.randles@intel.com, Honnappa.Nagarahalli@arm.com, ohilyard@iol.unh.edu, lijuan.tu@intel.com Cc: dev@dpdk.org, =?utf-8?q?Juraj_Linke=C5=A1?= Subject: [PATCH v1 8/8] dts: add main script for running dts Date: Wed, 22 Jun 2022 12:14:48 +0000 Message-Id: <20220622121448.3304251-9-juraj.linkes@pantheon.tech> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> References: <20220622121448.3304251-1-juraj.linkes@pantheon.tech> MIME-Version: 1.0 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 script is an interface to run DTS with standard argument parser. Signed-off-by: Juraj Linkeš --- dts/main.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100755 dts/main.py diff --git a/dts/main.py b/dts/main.py new file mode 100755 index 0000000000..af1f5e4d01 --- /dev/null +++ b/dts/main.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2010-2014 Intel Corporation +# + +""" +A test framework for testing DPDK. +""" + +import argparse + +from framework import dts + +# Read cmd-line args +parser = argparse.ArgumentParser(description="DPDK test framework.") + +parser.add_argument( + "--config-file", + default="execution.cfg", + help="configuration file that describes the test " + "cases, SUTs and targets", +) + +parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="enable verbose output, all message output on screen", +) + +args = parser.parse_args() + +# Main program begins here +dts.run_all( + args.config_file, + args.verbose, +)