ffdc: Add standalone FFDC collector script
- Set 1: 1st Pass: default to OpenBMC and SSH.
- Set 2: Remove trailing spaces.
- Set 3: Remove trailing spaces - part 2.
- Set 4: Address pycodestyle,
openbmc Python Coding Guidelines and review feedback issues.
- Set 5: more correction to meet pycodestyle.
- Set 6: Address review comments. Test scenarios were (re)executed.
- Set 7: Relocate all FFDC Collector files in ffdc/ dir.
Test scenarios were (re)executed with newly relocated files.
- Set 8: Make script progress, status more informative.
Add error handling, making error message more informative.
Add test for error scenarios.
Tested: 7 cli scenarios
(1) python3 <sandbox>/openbmc-test-automation/ffdc/collect_ffdc.py \
-h <> -u <> -p <> -f <sandbox>/openbmc-test-automation/ffdc/ffdc_config.yaml
(2) cd <sandbox>/openbmc-test-automation/ffdc
python3 collect_ffdc.py -h <> -u <> -p <>
(3) export OPENBMC_HOST=<>
export OPENBMC_USERNAME=<>
export OPENBMC_PASSWORD=<>
cd <sandbox>/openbmc-test-automation/ffdc
python3 collect_ffdc.py
(4) python3 collect_ffdc.py -h <invalid host>
(5) python3 collect_ffdc.py -u <invalid userid>
(6) python3 collect_ffdc.py -p <invalid password>
(7) python3 collect_ffdc.py -l <path with no access (/var, /opt)>
Change-Id: Ia26630168856341e749ce73b5cced831fc470219
Signed-off-by: Peter D Phan <peterp@us.ibm.com>
diff --git a/ffdc/ssh_utility.py b/ffdc/ssh_utility.py
new file mode 100644
index 0000000..51e8209
--- /dev/null
+++ b/ffdc/ssh_utility.py
@@ -0,0 +1,123 @@
+#!/usr/bin/env python
+
+import paramiko
+from paramiko.ssh_exception import AuthenticationException, NoValidConnectionsError, SSHException
+from paramiko.buffered_pipe import PipeTimeout as PipeTimeout
+import scp
+import socket
+from socket import timeout as SocketTimeout
+
+
+class SSHRemoteclient:
+ r"""
+ Class to create ssh connection to remote host
+ for remote host command execution and scp.
+ """
+
+ def __init__(self, hostname, username, password):
+
+ r"""
+ Description of argument(s):
+
+ hostname name/ip of the remote (targetting) host
+ username user on the remote host with access to FFCD files
+ password password for user on remote host
+ """
+
+ self.ssh_output = None
+ self.ssh_error = None
+ self.sshclient = None
+ self.scpclient = None
+ self.hostname = hostname
+ self.username = username
+ self.password = password
+
+ def ssh_remoteclient_login(self):
+
+ r"""
+ Method to create a ssh connection to remote host.
+ """
+
+ try:
+ # SSHClient to make connections to the remote server
+ self.sshclient = paramiko.SSHClient()
+ # setting set_missing_host_key_policy() to allow any host.
+ self.sshclient.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+ # Connect to the server
+ self.sshclient.connect(hostname=self.hostname,
+ username=self.username,
+ password=self.password)
+
+ except AuthenticationException:
+ print("\n>>>>>\tERROR: Authentication failed, please verify your login credentials")
+ except SSHException:
+ print("\n>>>>>\tERROR: Failures in SSH2 protocol negotiation or logic errors.")
+ except NoValidConnectionsError:
+ print('\n>>>>>\tERROR: No Valid SSH Connection after multiple attempts.')
+ except socket.error:
+ print("\n>>>>>\tERROR: SSH Connection refused.")
+ except Exception:
+ raise Exception("\n>>>>>\tERROR: Unexpected Exception.")
+
+ def ssh_remoteclient_disconnect(self):
+
+ r"""
+ Clean up.
+ """
+
+ if self.sshclient:
+ self.sshclient.close()
+
+ if self.scpclient:
+ self.scpclient.close()
+
+ def execute_command(self, command):
+ """
+ Execute command on the remote host.
+
+ Description of argument(s):
+ command Command string sent to remote host
+
+ """
+
+ try:
+ stdin, stdout, stderr = self.sshclient.exec_command(command)
+ stdout.channel.recv_exit_status()
+ response = stdout.readlines()
+ return response
+ except (paramiko.AuthenticationException, paramiko.SSHException,
+ paramiko.ChannelException) as ex:
+ print("\n>>>>>\tERROR: Remote command execution fails.")
+
+ def scp_connection(self):
+
+ r"""
+ Create a scp connection for file transfer.
+ """
+ self.scpclient = scp.SCPClient(self.sshclient.get_transport())
+
+ def scp_file_from_remote(self, remote_file, local_file):
+
+ r"""
+ scp file in remote system to local with date-prefixed filename.
+
+ Description of argument(s):
+ remote_file Full path filename on the remote host
+
+ local_file Full path filename on the local host
+ local filename = date-time_remote filename
+
+ """
+
+ try:
+ self.scpclient.get(remote_file, local_file)
+ except scp.SCPException:
+ print("scp.SCPException scp %s from remotehost" % remote_file)
+ return False
+ except (SocketTimeout, PipeTimeout) as ex:
+ # Future enhancement: multiple retries on these exceptions due to bad ssh connection
+ print("Timeout scp %s from remotehost" % remote_file)
+ return False
+
+ # Return True for file accounting
+ return True