| #!/usr/bin/env python |
| |
| import paramiko |
| from paramiko.ssh_exception import AuthenticationException |
| from paramiko.ssh_exception import NoValidConnectionsError |
| from paramiko.ssh_exception import SSHException |
| from paramiko.ssh_exception import BadHostKeyException |
| from paramiko.buffered_pipe import PipeTimeout as PipeTimeout |
| from scp import SCPClient, SCPException |
| import time |
| import socket |
| import logging |
| 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 (targeting) 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. |
| """ |
| |
| is_ssh_login = True |
| 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, |
| look_for_keys=False) |
| |
| except (BadHostKeyException, AuthenticationException, |
| SSHException, NoValidConnectionsError, socket.error) as e: |
| is_ssh_login = False |
| |
| return is_ssh_login |
| |
| 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, |
| default_timeout=60): |
| """ |
| Execute command on the remote host. |
| |
| Description of argument(s): |
| command Command string sent to remote host |
| |
| """ |
| |
| empty = '' |
| cmd_start = time.time() |
| try: |
| stdin, stdout, stderr = \ |
| self.sshclient.exec_command(command, timeout=default_timeout) |
| start = time.time() |
| while time.time() < start + default_timeout: |
| if stdout.channel.exit_status_ready(): |
| break |
| time.sleep(1) |
| cmd_exit_code = stdout.channel.recv_exit_status() |
| return cmd_exit_code, stderr.readlines(), stdout.readlines() |
| |
| except (paramiko.AuthenticationException, paramiko.SSHException, |
| paramiko.ChannelException, SocketTimeout) as e: |
| # Log command with error. Return to caller for next command, if any. |
| logging.error("\n\tERROR: Fail remote command %s %s" % (e.__class__, e)) |
| logging.error("\tCommand '%s' Elapsed Time %s" % |
| (command, time.strftime("%H:%M:%S", time.gmtime(time.time() - cmd_start)))) |
| return 0, empty, empty |
| |
| def scp_connection(self): |
| |
| r""" |
| Create a scp connection for file transfer. |
| """ |
| try: |
| self.scpclient = SCPClient(self.sshclient.get_transport(), sanitize=lambda x: x) |
| logging.info("\n\t[Check] %s SCP transport established.\t [OK]" % self.hostname) |
| except (SCPException, SocketTimeout, PipeTimeout) as e: |
| self.scpclient = None |
| logging.error("\n\tERROR: SCP get_transport has failed. %s %s" % (e.__class__, e)) |
| logging.info("\tScript continues generating FFDC on %s." % self.hostname) |
| logging.info("\tCollected data will need to be manually offloaded.") |
| |
| 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, recursive=True) |
| except (SCPException, SocketTimeout, PipeTimeout) as e: |
| # Log command with error. Return to caller for next file, if any. |
| logging.error( |
| "\n\tERROR: Fail scp %s from remotehost %s %s\n\n" % (remote_file, e.__class__, e)) |
| return False |
| |
| # Return True for file accounting |
| return True |