ffdc: Implement for use with Telnet protocol
- Set 1: First pass for comments and feedback.
- Set 2: Adjust timeout/waittime calculation
Test:
- Set 1: Test telnet protocol
- Set 2: Test telnet protocol. Regression test other protocols.
Signed-off-by: Peter D Phan <peterp@us.ibm.com>
Change-Id: Ifbf317fa8dbe3b5a8ba5cbea1fbd4bf4f6c6ba63
diff --git a/ffdc/ffdc_collector.py b/ffdc/ffdc_collector.py
index 3ef0072..121cb74 100644
--- a/ffdc/ffdc_collector.py
+++ b/ffdc/ffdc_collector.py
@@ -12,6 +12,7 @@
from errno import EACCES, EPERM
import subprocess
from ssh_utility import SSHRemoteclient
+from telnet_utility import TelnetRemoteclient
class FFDCCollector:
@@ -47,7 +48,8 @@
self.password = password
self.ffdc_config = ffdc_config
self.location = location
- self.remote_client = None
+ self.ssh_remoteclient = None
+ self.telnet_remoteclient = None
self.ffdc_dir_path = ""
self.ffdc_prefix = ""
self.target_type = remote_type.upper()
@@ -129,12 +131,17 @@
else:
print("\n\t[Check] %s Redfish Service.\t\t [NOT AVAILABLE]" % self.hostname)
+ # IPMI
if self.verify_ipmi():
working_protocol_list.append("IPMI")
print("\n\t[Check] %s IPMI LAN Service.\t\t [OK]" % self.hostname)
else:
print("\n\t[Check] %s IPMI LAN Service.\t\t [NOT AVAILABLE]" % self.hostname)
+ # Telnet
+ if self.telnet_to_target_system():
+ working_protocol_list.append("TELNET")
+
# Verify top level directory exists for storage
self.validate_local_store(self.location)
print("\n\t---- Completed protocol pre-requisite check ----\n")
@@ -154,18 +161,35 @@
"""
- self.remoteclient = SSHRemoteclient(self.hostname,
- self.username,
- self.password)
+ self.ssh_remoteclient = SSHRemoteclient(self.hostname,
+ self.username,
+ self.password)
- self.remoteclient.ssh_remoteclient_login()
- print("\n\t[Check] %s SSH connection established.\t [OK]" % self.hostname)
+ if self.ssh_remoteclient.ssh_remoteclient_login():
+ print("\n\t[Check] %s SSH connection established.\t [OK]" % self.hostname)
- # Check scp connection.
- # If scp connection fails,
- # continue with FFDC generation but skip scp files to local host.
- self.remoteclient.scp_connection()
- return True
+ # Check scp connection.
+ # If scp connection fails,
+ # continue with FFDC generation but skip scp files to local host.
+ self.ssh_remoteclient.scp_connection()
+ return True
+ else:
+ print("\n\t[Check] %s SSH connection.\t [NOT AVAILABLE]" % self.hostname)
+ return False
+
+ def telnet_to_target_system(self):
+ r"""
+ Open a telnet connection to targeted system.
+ """
+ self.telnet_remoteclient = TelnetRemoteclient(self.hostname,
+ self.username,
+ self.password)
+ if self.telnet_remoteclient.tn_remoteclient_login():
+ print("\n\t[Check] %s Telnet connection established.\t [OK]" % self.hostname)
+ return True
+ else:
+ print("\n\t[Check] %s Telnet connection.\t [NOT AVAILABLE]" % self.hostname)
+ return False
def generate_ffdc(self, working_protocol_list):
r"""
@@ -205,6 +229,12 @@
else:
print("\n\tERROR: SSH or SCP is not available for %s." % self.hostname)
+ if ffdc_actions[machine_type][k]['PROTOCOL'][0] == 'TELNET':
+ if 'TELNET' in working_protocol_list:
+ self.protocol_telnet(ffdc_actions, machine_type, k)
+ else:
+ print("\n\tERROR: TELNET is not available for %s." % self.hostname)
+
if ffdc_actions[machine_type][k]['PROTOCOL'][0] == 'REDFISH':
if 'REDFISH' in working_protocol_list:
self.protocol_redfish(ffdc_actions, machine_type, k)
@@ -219,7 +249,8 @@
# Close network connection after collecting all files
self.elapsed_time = time.strftime("%H:%M:%S", time.gmtime(time.time() - self.start_time))
- self.remoteclient.ssh_remoteclient_disconnect()
+ self.ssh_remoteclient.ssh_remoteclient_disconnect()
+ self.telnet_remoteclient.tn_remoteclient_disconnect()
def protocol_ssh(self,
ffdc_actions,
@@ -239,6 +270,44 @@
else:
self.collect_and_copy_ffdc(ffdc_actions[machine_type][sub_type])
+ def protocol_telnet(self,
+ ffdc_actions,
+ machine_type,
+ sub_type):
+ r"""
+ Perform actions using telnet protocol.
+ Description of argument(s):
+ ffdc_actions List of actions from ffdc_config.yaml.
+ machine_type OS Type of remote host.
+ """
+ print("\n\t[Run] Executing commands on %s using %s" % (self.hostname, 'TELNET'))
+ telnet_files_saved = []
+ progress_counter = 0
+ list_of_commands = ffdc_actions[machine_type][sub_type]['COMMANDS']
+ for index, each_cmd in enumerate(list_of_commands, start=0):
+ command_txt, command_timeout = self.unpack_command(each_cmd)
+ result = self.telnet_remoteclient.execute_command(command_txt, command_timeout)
+ if result:
+ try:
+ targ_file = ffdc_actions[machine_type][sub_type]['FILES'][index]
+ except IndexError:
+ targ_file = each_cmd
+ print("\n\t[WARN] Missing filename to store data from telnet %s." % each_cmd)
+ print("\t[WARN] Data will be stored in %s." % targ_file)
+ targ_file_with_path = (self.ffdc_dir_path
+ + self.ffdc_prefix
+ + targ_file)
+ # Creates a new file
+ with open(targ_file_with_path, 'wb') as fp:
+ fp.write(result)
+ fp.close
+ telnet_files_saved.append(targ_file)
+ progress_counter += 1
+ self.print_progress(progress_counter)
+ print("\n\t[Run] Commands execution completed.\t\t [OK]")
+ for file in telnet_files_saved:
+ print("\n\t\tSuccessfully save file " + file + ".")
+
def protocol_redfish(self,
ffdc_actions,
machine_type,
@@ -351,7 +420,7 @@
form_filename)
# Copying files
- if self.remoteclient.scpclient:
+ if self.ssh_remoteclient.scpclient:
print("\n\n\tCopying FFDC files from remote system %s.\n" % self.hostname)
# Retrieving files from target system
@@ -388,6 +457,24 @@
list_of_files = []
return list_of_files
+ def unpack_command(self,
+ command):
+ r"""
+ Unpack command from config file
+
+ Description of argument(s):
+ command Command from config file.
+ """
+ if isinstance(command, dict):
+ command_txt = next(iter(command))
+ command_timeout = next(iter(command.values()))
+ elif isinstance(command, str):
+ command_txt = command
+ # Default command timeout 60 seconds
+ command_timeout = 60
+
+ return command_txt, command_timeout
+
def ssh_execute_ffdc_commands(self,
ffdc_actions_for_machine_type,
form_filename=False):
@@ -408,18 +495,12 @@
progress_counter = 0
for command in list_of_commands:
- if isinstance(command, dict):
- command_txt = next(iter(command))
- command_timeout = next(iter(command.values()))
- elif isinstance(command, str):
- command_txt = command
- # Default ssh command timeout 60 seconds
- command_timeout = 60
+ command_txt, command_timeout = self.unpack_command(command)
if form_filename:
command_txt = str(command_txt % self.target_type)
- err, response = self.remoteclient.execute_command(command_txt, command_timeout)
+ err, response = self.ssh_remoteclient.execute_command(command_txt, command_timeout)
progress_counter += 1
self.print_progress(progress_counter)
@@ -435,7 +516,7 @@
ffdc_actions_for_machine_type commands and files for the selected remote host type.
"""
- if self.remoteclient.scpclient:
+ if self.ssh_remoteclient.scpclient:
print("\n\tCopying DUMP files from remote system %s.\n" % self.hostname)
list_of_commands = self.get_command_list(ffdc_actions_for_machine_type)
@@ -450,10 +531,10 @@
print("\t\tInvalid command %s for DUMP_LOGS block." % command)
continue
- err, response = self.remoteclient.execute_command(command)
+ err, response = self.ssh_remoteclient.execute_command(command)
if response:
- scp_result = self.remoteclient.scp_file_from_remote(filename, self.ffdc_dir_path)
+ scp_result = self.ssh_remoteclient.scp_file_from_remote(filename, self.ffdc_dir_path)
if scp_result:
print("\t\tSuccessfully copied from " + self.hostname + ':' + filename)
else:
@@ -488,9 +569,9 @@
# If source file name contains wild card, copy filename as is.
if '*' in source_file_path:
- scp_result = self.remoteclient.scp_file_from_remote(source_file_path, self.ffdc_dir_path)
+ scp_result = self.ssh_remoteclient.scp_file_from_remote(source_file_path, self.ffdc_dir_path)
else:
- scp_result = self.remoteclient.scp_file_from_remote(source_file_path, targ_file_path)
+ scp_result = self.ssh_remoteclient.scp_file_from_remote(source_file_path, targ_file_path)
if not quiet:
if scp_result:
diff --git a/ffdc/ssh_utility.py b/ffdc/ssh_utility.py
index 56d4dad..9715948 100644
--- a/ffdc/ssh_utility.py
+++ b/ffdc/ssh_utility.py
@@ -7,7 +7,6 @@
from paramiko.ssh_exception import BadHostKeyException
from paramiko.buffered_pipe import PipeTimeout as PipeTimeout
from scp import SCPClient, SCPException
-import sys
import time
import socket
from socket import timeout as SocketTimeout
@@ -43,6 +42,7 @@
Method to create a ssh connection to remote host.
"""
+ is_ssh_login = True
try:
# SSHClient to make connections to the remote server
self.sshclient = paramiko.SSHClient()
@@ -56,8 +56,9 @@
except (BadHostKeyException, AuthenticationException,
SSHException, NoValidConnectionsError, socket.error) as e:
- print("\n>>>>>\tERROR: Unable to SSH to %s %s %s\n\n" % (self.hostname, e.__class__, e))
- sys.exit(-1)
+ is_ssh_login = False
+
+ return is_ssh_login
def ssh_remoteclient_disconnect(self):
diff --git a/ffdc/telnet_utility.py b/ffdc/telnet_utility.py
index 29698eb..8635bf0 100644
--- a/ffdc/telnet_utility.py
+++ b/ffdc/telnet_utility.py
@@ -1,5 +1,7 @@
#!/usr/bin/env python
+
+import time
import socket
import telnetlib
from collections import deque
@@ -73,8 +75,6 @@
pass
def execute_command(self, cmd,
- rtnpartial=False,
- wait_cnt=5,
i_timeout=300):
r'''
@@ -91,44 +91,21 @@
'''
# Execute the command and read the command output
+ # Execute the command and read the command output
+ return_buffer = b''
try:
# Flush whatever data is in the read buffer by doing
# a non-blocking read
- self.tnclient.read_very_eager()
+ self.tnclient.read_very_eager().decode('utf-8')
# Execute the command
- self.tnclient.write(cmd.encode('utf-8') + b"\n")
+ self.tnclient.write(cmd.encode('utf-8') + b'\n')
+ time.sleep(i_timeout)
- # Read the command output. Read until we get command prompt
- l_buf = ''
- l_xcnt = 0
- while(True):
- index, match, b = self.tnclient.expect([br'\$', br'\#'], i_timeout)
+ # Read the command output.
+ return_buffer = self.tnclient.read_very_eager()
- if(b == ''):
- # Nothing read. Increment the counter & retry.
- l_xcnt = l_xcnt + 1
- if(l_xcnt >= wait_cnt):
- l_time_waited = str((l_xcnt * i_timeout) / 60)
- print("\t\t ERROR Timeout execute Telnet command")
- break
- else:
- # We got some data. Reset the counter.
- l_xcnt = 0
- l_buf = l_buf + b.decode('utf-8').strip()
-
- if (index != -1) and (match is not None):
- # We got the command prompt. Have read the complete command
- # output.
- break
-
- if rtnpartial:
- print("\t\t WARN "
- + "Have not read the command prompt. "
- + "Returning command output read.")
-
- return l_buf
except (socket.error, EOFError) as e:
self.tn_remoteclient_disconnect()
@@ -137,11 +114,8 @@
elif str(e).__contains__("telnet connection closed"):
msg = "Telnet connection closed."
else:
- msg = "Some other issue. Connection got reset!!"
+ msg = "Some other issue.%s %s %s\n\n" % (cmd, e.__class__, e)
print("\t\t ERROR %s " % msg)
- return ''
- # Remove command prompt
- c = l_buf[0: (len(l_buf) - 1)]
- return c
+ return return_buffer