blob: 01b39dd1fc3bd8d31d2e93b5afc5b6a8d954f3cb [file] [log] [blame]
#!/usr/bin/env python3
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,
banner_timeout=120,
timeout=60,
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:
# Need to do read/write operation to trigger
# paramiko exec_command timeout mechanism.
xresults = stderr.readlines()
results = ''.join(xresults)
time.sleep(1)
if stdout.channel.exit_status_ready():
break
cmd_exit_code = stdout.channel.recv_exit_status()
# Convert list of string to one string
err = ''
out = ''
for item in results:
err += item
for item in stdout.readlines():
out += item
return cmd_exit_code, err, out
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, SSHException) 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))
# Pause for 2 seconds allowing Paramiko to finish error processing before next fetch.
# Without the delay after SCPException,
# next fetch will get 'paramiko.ssh_exception.SSHException'> Channel closed Error.
time.sleep(2)
return False
# Return True for file accounting
return True