xref: /openbmc/openbmc-test-automation/ffdc/lib/telnet_utility.py (revision 20f38712b324e61a94e174017c487a0af4b373e1)
1e7e9171eSGeorge Keishing#!/usr/bin/env python3
2fd260e47SPeter D  Phan
3fd260e47SPeter D  Phan
4e635ddc0SGeorge Keishingimport logging
5*20f38712SPatrick Williamsimport socket
6e635ddc0SGeorge Keishingimport telnetlib
7*20f38712SPatrick Williamsimport time
8fd260e47SPeter D  Phanfrom collections import deque
9fd260e47SPeter D  Phan
10fd260e47SPeter D  Phan
11fd260e47SPeter D  Phanclass TelnetRemoteclient:
12fd260e47SPeter D  Phan    r"""
13fd260e47SPeter D  Phan    Class to create telnet connection to remote host for command execution.
14fd260e47SPeter D  Phan    """
15fd260e47SPeter D  Phan
16*20f38712SPatrick Williams    def __init__(
17*20f38712SPatrick Williams        self, hostname, username, password, port=23, read_timeout=None
18*20f38712SPatrick Williams    ):
19fd260e47SPeter D  Phan        r"""
20fd260e47SPeter D  Phan        Description of argument(s):
21fd260e47SPeter D  Phan
22fd260e47SPeter D  Phan        hostname        Name/IP of the remote (targeting) host
23fd260e47SPeter D  Phan        username        User on the remote host with access to FFCD files
24fd260e47SPeter D  Phan        password        Password for user on remote host
25fd260e47SPeter D  Phan        read_timeout    New read timeout value to override default one
26fd260e47SPeter D  Phan        """
27fd260e47SPeter D  Phan
28fd260e47SPeter D  Phan        self.hostname = hostname
29fd260e47SPeter D  Phan        self.username = username
30fd260e47SPeter D  Phan        self.password = password
31fd260e47SPeter D  Phan        self.tnclient = None
32fd260e47SPeter D  Phan        self.port = port
33fd260e47SPeter D  Phan        self.read_timeout = read_timeout
34fd260e47SPeter D  Phan
35fd260e47SPeter D  Phan    def tn_remoteclient_login(self):
36fd260e47SPeter D  Phan        is_telnet = True
37fd260e47SPeter D  Phan        try:
38*20f38712SPatrick Williams            self.tnclient = telnetlib.Telnet(
39*20f38712SPatrick Williams                self.hostname, self.port, timeout=15
40*20f38712SPatrick Williams            )
41*20f38712SPatrick Williams            if b"login:" in self.tnclient.read_until(
42*20f38712SPatrick Williams                b"login:", timeout=self.read_timeout
43*20f38712SPatrick Williams            ):
44*20f38712SPatrick Williams                self.tnclient.write(self.username.encode("utf-8") + b"\n")
45fd260e47SPeter D  Phan
46*20f38712SPatrick Williams                if b"Password:" in self.tnclient.read_until(
47*20f38712SPatrick Williams                    b"Password:", timeout=self.read_timeout
48*20f38712SPatrick Williams                ):
49*20f38712SPatrick Williams                    self.tnclient.write(self.password.encode("utf-8") + b"\n")
50fd260e47SPeter D  Phan
51*20f38712SPatrick Williams                    n, match, pre_match = self.tnclient.expect(
52*20f38712SPatrick Williams                        [
53*20f38712SPatrick Williams                            b"Login incorrect",
54*20f38712SPatrick Williams                            b"invalid login name or password.",
55*20f38712SPatrick Williams                            rb"\#",
56*20f38712SPatrick Williams                            rb"\$",
57*20f38712SPatrick Williams                        ],
58*20f38712SPatrick Williams                        timeout=self.read_timeout,
59*20f38712SPatrick Williams                    )
60fd260e47SPeter D  Phan                    if n == 0 or n == 1:
61fd260e47SPeter D  Phan                        logging.error(
62*20f38712SPatrick Williams                            "\n\tERROR: Telnet Authentication Failed.  Check"
63*20f38712SPatrick Williams                            " userid and password.\n\n"
64*20f38712SPatrick Williams                        )
65fd260e47SPeter D  Phan                        is_telnet = False
66fd260e47SPeter D  Phan                    else:
67fd260e47SPeter D  Phan                        # login successful
68fd260e47SPeter D  Phan                        self.fifo = deque()
69fd260e47SPeter D  Phan                else:
70fd260e47SPeter D  Phan                    # Anything else, telnet server is not running
71fd260e47SPeter D  Phan                    logging.error("\n\tERROR: Telnet Connection Refused.\n\n")
72fd260e47SPeter D  Phan                    is_telnet = False
73fd260e47SPeter D  Phan            else:
74fd260e47SPeter D  Phan                is_telnet = False
75fd260e47SPeter D  Phan        except Exception:
76fd260e47SPeter D  Phan            # Any kind of exception, skip telnet protocol
77fd260e47SPeter D  Phan            is_telnet = False
78fd260e47SPeter D  Phan
79fd260e47SPeter D  Phan        return is_telnet
80fd260e47SPeter D  Phan
81fd260e47SPeter D  Phan    def __del__(self):
82fd260e47SPeter D  Phan        self.tn_remoteclient_disconnect()
83fd260e47SPeter D  Phan
84fd260e47SPeter D  Phan    def tn_remoteclient_disconnect(self):
85fd260e47SPeter D  Phan        try:
86fd260e47SPeter D  Phan            self.tnclient.close()
87fd260e47SPeter D  Phan        except Exception:
88fd260e47SPeter D  Phan            # the telnet object might not exist yet, so ignore this one
89fd260e47SPeter D  Phan            pass
90fd260e47SPeter D  Phan
91*20f38712SPatrick Williams    def execute_command(self, cmd, i_timeout=120):
92*20f38712SPatrick Williams        r"""
93fd260e47SPeter D  Phan        Executes commands on the remote host
94fd260e47SPeter D  Phan
95fd260e47SPeter D  Phan        Description of argument(s):
96fd260e47SPeter D  Phan        cmd             Command to run on remote host
97fd260e47SPeter D  Phan        i_timeout       Timeout for command output
981627d961SPeter D  Phan                        default is 120 seconds
99*20f38712SPatrick Williams        """
100fd260e47SPeter D  Phan
1011627d961SPeter D  Phan        # Wait time for command execution before reading the output.
1021627d961SPeter D  Phan        # Use user input wait time for command execution if one exists.
1031627d961SPeter D  Phan        # Else use the default 120 sec,
1041627d961SPeter D  Phan        if i_timeout != 120:
1051627d961SPeter D  Phan            execution_time = i_timeout
1061627d961SPeter D  Phan        else:
1071627d961SPeter D  Phan            execution_time = 120
1081627d961SPeter D  Phan
1091627d961SPeter D  Phan        # Execute the command and read the command output.
110*20f38712SPatrick Williams        return_buffer = b""
111fd260e47SPeter D  Phan        try:
1121627d961SPeter D  Phan            # Do at least one non-blocking read.
113fd260e47SPeter D  Phan            #  to flush whatever data is in the read buffer.
114fd260e47SPeter D  Phan            while self.tnclient.read_very_eager():
115fd260e47SPeter D  Phan                continue
116fd260e47SPeter D  Phan
117fd260e47SPeter D  Phan            # Execute the command
118*20f38712SPatrick Williams            self.tnclient.write(cmd.encode("utf-8") + b"\n")
1191627d961SPeter D  Phan            time.sleep(execution_time)
120fd260e47SPeter D  Phan
121*20f38712SPatrick Williams            local_buffer = b""
122fd260e47SPeter D  Phan            # Read the command output one block at a time.
123fd260e47SPeter D  Phan            return_buffer = self.tnclient.read_very_eager()
124fd260e47SPeter D  Phan            while return_buffer:
125*20f38712SPatrick Williams                local_buffer = b"".join([local_buffer, return_buffer])
126fd260e47SPeter D  Phan                time.sleep(3)  # let the buffer fill up a bit
127fd260e47SPeter D  Phan                return_buffer = self.tnclient.read_very_eager()
128fd260e47SPeter D  Phan        except (socket.error, EOFError) as e:
129fd260e47SPeter D  Phan            self.tn_remoteclient_disconnect()
130fd260e47SPeter D  Phan
131fd260e47SPeter D  Phan            if str(e).__contains__("Connection reset by peer"):
132fd260e47SPeter D  Phan                msg = e
133fd260e47SPeter D  Phan            elif str(e).__contains__("telnet connection closed"):
134fd260e47SPeter D  Phan                msg = "Telnet connection closed."
135fd260e47SPeter D  Phan            else:
136fd260e47SPeter D  Phan                msg = "Some other issue.%s %s %s\n\n" % (cmd, e.__class__, e)
137fd260e47SPeter D  Phan
138fd260e47SPeter D  Phan            logging.error("\t\t ERROR %s " % msg)
139fd260e47SPeter D  Phan
140b76e1753SPeter D  Phan        # Return ASCII string data with ending PROMPT stripped
141*20f38712SPatrick Williams        return local_buffer.decode("ascii", "ignore").replace("$ ", "\n")
142