All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Juraj Linkeš" <juraj.linkes@pantheon.tech>
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, "Juraj Linkeš" <juraj.linkes@pantheon.tech>
Subject: [PATCH v1 1/8] dts: add ssh pexpect library
Date: Wed, 22 Jun 2022 12:14:41 +0000	[thread overview]
Message-ID: <20220622121448.3304251-2-juraj.linkes@pantheon.tech> (raw)
In-Reply-To: <20220622121448.3304251-1-juraj.linkes@pantheon.tech>

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š <juraj.linkes@pantheon.tech>
---
 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"
-- 
2.20.1


  reply	other threads:[~2022-06-22 12:15 UTC|newest]

Thread overview: 105+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-22 12:14 [PATCH v1 0/8] dts: ssh connection to a node Juraj Linkeš
2022-06-22 12:14 ` Juraj Linkeš [this message]
2022-06-22 12:14 ` [PATCH v1 2/8] dts: add locks for parallel node connections Juraj Linkeš
2022-06-22 12:14 ` [PATCH v1 3/8] dts: add ssh connection extension Juraj Linkeš
2022-06-22 12:14 ` [PATCH v1 4/8] dts: add basic logging facility Juraj Linkeš
2022-06-22 12:14 ` [PATCH v1 5/8] dts: add Node base class Juraj Linkeš
2022-06-22 12:14 ` [PATCH v1 6/8] dts: add config parser module Juraj Linkeš
2022-06-22 12:14 ` [PATCH v1 7/8] dts: add dts runtime workflow module Juraj Linkeš
2022-06-22 12:14 ` [PATCH v1 8/8] dts: add main script for running dts Juraj Linkeš
2022-07-11 14:51 ` [PATCH v2 0/8] ssh connection to a node Juraj Linkeš
2022-07-11 14:51   ` [PATCH v2 1/8] dts: add basic logging facility Juraj Linkeš
2022-07-11 14:51   ` [PATCH v2 2/8] dts: add ssh pexpect library Juraj Linkeš
2022-07-11 14:51   ` [PATCH v2 3/8] dts: add locks for parallel node connections Juraj Linkeš
2022-07-11 14:51   ` [PATCH v2 4/8] dts: add ssh connection extension Juraj Linkeš
2022-07-11 14:51   ` [PATCH v2 5/8] dts: add config parser module Juraj Linkeš
2022-07-11 14:51   ` [PATCH v2 6/8] dts: add Node base class Juraj Linkeš
2022-07-11 14:51   ` [PATCH v2 7/8] dts: add dts workflow module Juraj Linkeš
2022-07-11 14:51   ` [PATCH v2 8/8] dts: add dts executable script Juraj Linkeš
2022-07-28 10:00   ` [PATCH v3 0/9] dts: ssh connection to a node Juraj Linkeš
2022-07-28 10:00     ` [PATCH v3 1/9] dts: add project tools config Juraj Linkeš
2022-07-28 10:00     ` [PATCH v3 2/9] dts: add developer tools Juraj Linkeš
2022-07-28 10:00     ` [PATCH v3 3/9] dts: add basic logging facility Juraj Linkeš
2022-07-28 10:00     ` [PATCH v3 4/9] dts: add ssh pexpect library Juraj Linkeš
2022-07-28 10:00     ` [PATCH v3 5/9] dts: add ssh connection extension Juraj Linkeš
2022-07-28 10:00     ` [PATCH v3 6/9] dts: add config parser module Juraj Linkeš
2022-07-28 10:00     ` [PATCH v3 7/9] dts: add Node base class Juraj Linkeš
2022-07-28 10:00     ` [PATCH v3 8/9] dts: add dts workflow module Juraj Linkeš
2022-07-28 10:00     ` [PATCH v3 9/9] dts: add dts executable script Juraj Linkeš
2022-07-29 10:55     ` [PATCH v4 0/9] dts: ssh connection to a node Juraj Linkeš
2022-07-29 10:55       ` [PATCH v4 1/9] dts: add project tools config Juraj Linkeš
2022-08-10  6:30         ` Tu, Lijuan
2022-09-07 16:16         ` Bruce Richardson
2022-09-09 13:38           ` Juraj Linkeš
2022-09-09 13:52             ` Bruce Richardson
2022-09-09 14:13               ` Juraj Linkeš
2022-09-12 14:06                 ` Owen Hilyard
2022-09-12 15:15                   ` Bruce Richardson
2022-09-13 12:08                     ` Juraj Linkeš
2022-09-13 14:18                       ` Bruce Richardson
2022-09-13 19:03                     ` Honnappa Nagarahalli
2022-09-13 19:19                 ` Honnappa Nagarahalli
2022-09-14  9:37                   ` Thomas Monjalon
2022-09-14 12:55                     ` Juraj Linkeš
2022-09-14 13:11                       ` Bruce Richardson
2022-09-14 14:28                         ` Thomas Monjalon
2022-09-21 10:49                           ` Juraj Linkeš
2022-09-13 19:11             ` Honnappa Nagarahalli
2022-07-29 10:55       ` [PATCH v4 2/9] dts: add developer tools Juraj Linkeš
2022-08-10  6:30         ` Tu, Lijuan
2022-09-07 16:37         ` Bruce Richardson
2022-09-13 12:38           ` Juraj Linkeš
2022-09-13 20:38             ` Honnappa Nagarahalli
2022-09-14  7:37               ` Bruce Richardson
2022-09-14 12:45               ` Juraj Linkeš
2022-09-14 13:13                 ` Bruce Richardson
2022-09-14 14:26                   ` Thomas Monjalon
2022-09-14 19:08                     ` Honnappa Nagarahalli
2022-09-20 12:14                       ` Juraj Linkeš
2022-09-20 12:22                         ` Tu, Lijuan
2022-07-29 10:55       ` [PATCH v4 3/9] dts: add basic logging facility Juraj Linkeš
2022-08-10  6:31         ` Tu, Lijuan
2022-09-08  8:31         ` Bruce Richardson
2022-09-13 12:52           ` Juraj Linkeš
2022-09-13 23:31             ` Honnappa Nagarahalli
2022-09-14 12:51               ` Juraj Linkeš
2022-07-29 10:55       ` [PATCH v4 4/9] dts: add ssh pexpect library Juraj Linkeš
2022-08-10  6:31         ` Tu, Lijuan
2022-09-08  9:53         ` Bruce Richardson
2022-09-13 13:36           ` Juraj Linkeš
2022-09-13 14:23             ` Bruce Richardson
2022-09-13 14:59         ` Stanislaw Kardach
2022-09-13 17:23           ` Owen Hilyard
2022-09-14  0:03             ` Honnappa Nagarahalli
2022-09-14  7:42               ` Bruce Richardson
2022-09-14  7:58                 ` Stanislaw Kardach
2022-09-14 19:57                 ` Honnappa Nagarahalli
2022-09-19 14:21                   ` Owen Hilyard
2022-09-20 17:54                     ` Honnappa Nagarahalli
2022-09-21  1:01                       ` Tu, Lijuan
2022-09-21  5:37                       ` Jerin Jacob
2022-09-22  9:03                         ` Juraj Linkeš
2022-09-14  9:42         ` Stanislaw Kardach
2022-09-22  9:41           ` Juraj Linkeš
2022-09-22 14:32             ` Stanislaw Kardach
2022-09-23  7:22               ` Juraj Linkeš
2022-09-23  8:15                 ` Bruce Richardson
2022-09-23 10:18                   ` Stanislaw Kardach
2022-07-29 10:55       ` [PATCH v4 5/9] dts: add ssh connection extension Juraj Linkeš
2022-08-10  6:32         ` Tu, Lijuan
2022-09-13 17:04         ` Bruce Richardson
2022-09-13 17:32           ` Owen Hilyard
2022-09-14  7:46             ` Bruce Richardson
2022-09-14 12:02               ` Owen Hilyard
2022-09-14 13:15                 ` Bruce Richardson
2022-07-29 10:55       ` [PATCH v4 6/9] dts: add config parser module Juraj Linkeš
2022-08-10  6:33         ` Tu, Lijuan
2022-09-13 17:19         ` Bruce Richardson
2022-09-13 17:47           ` Owen Hilyard
2022-09-14  7:48             ` Bruce Richardson
2022-07-29 10:55       ` [PATCH v4 7/9] dts: add Node base class Juraj Linkeš
2022-08-10  6:33         ` Tu, Lijuan
2022-07-29 10:55       ` [PATCH v4 8/9] dts: add dts workflow module Juraj Linkeš
2022-08-10  6:34         ` Tu, Lijuan
2022-07-29 10:55       ` [PATCH v4 9/9] dts: add dts executable script Juraj Linkeš
2022-08-10  6:35         ` Tu, Lijuan

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=20220622121448.3304251-2-juraj.linkes@pantheon.tech \
    --to=juraj.linkes@pantheon.tech \
    --cc=Honnappa.Nagarahalli@arm.com \
    --cc=david.marchand@redhat.com \
    --cc=dev@dpdk.org \
    --cc=jerinjacobk@gmail.com \
    --cc=lijuan.tu@intel.com \
    --cc=ohilyard@iol.unh.edu \
    --cc=ronan.randles@intel.com \
    --cc=thomas@monjalon.net \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.