Implementation of the function of forcing paramiko library to exit at a given time when executing commands
- 2021-09-12 01:37:22
- OfStack
When using paramiko library ssh to connect to a remote cloud host, it is very occasionally stuck, and the connection cannot be exited (it can be caused by the restart of the cloud host when executing commands, etc.). It takes a given period of time to exit the connection regardless of whether the command execution is stuck or not, showing a command execution timeout error.
Implementation method:
Thread + event, execute ssh command in thread, and configure timeout time for event.
Code example:
1 from threading import Thread, Event
2 import paramiko
class SshClient(object):
def __init__(self, ip, port, username, password):
self.ip = ip
self.host = host
self.username = username
self.password = password
def exec_command(cmd, timeout):
log.info(u" In ip:%s Execute commands on %s" % (self.ip, cmd))
sc = paramiko.SSHClient()
sc.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# Used to receive stdout stderror status Information
res = [None, None, None]
def get_return(start_event, res_list):
_, cmd_stdout, cmd_stderr = sc.exec_command(command=cmd, timeout=timeout)
channel = cmd_stdout.channel
cmd_status = channel.recv_exit_status()
res_list[0] = cmd_stdout
res_list[1] = cmd_stderr
res_list[2] = cmd_status
start_event.set() # Indicates that the thread has finished executing
try:
sc.connect(hostname=self.ip, port=self.port, username=self.username, password=self.password, timeout=30) # Here's timeout Is used by connection, which is different from what we want
start_evt = Event()
t = Thread(target=get_return, args=(start_evt, res))
t.start()
start_evt.wait(timeout=timeout)
# Execution here indicates that the thread has exited
if None in res:
raise Exception(u" Command timed out ")
stdout, stderr, status = res
if status != 0:
raise Exception(u" Command execution returns non- 0 ! The return value is %s, The error message is %s" % (status, stdout.read() + stderr.read()))
return stdout.read() + stderr.read()
finally:
sc.close()
}
Knowledge point supplement:
Introduction of python paramiko
1: Use paramiko
# Set the remote host address and port for an ssh connection
t=paramiko.Transport((ip,port))
# Set the login name and password
t.connect(username=username,password=password)
# Open 1 channel after successful connection
chan=t.open_session()
# Set session timeout
chan.settimeout(session_timeout)
# Open remote terminal
chan.get_pty()
# Activate terminal
chan.invoke_shell()
You can then execute commands remotely and get feedback locally through chan. send ('command') and chan. recv (recv_buffer).
2: Introduction to two modules of paramiko
paramiko has two modules, SSHClient () and SFTPClient ()
Use code for SSHClient ():
import paramiko
ssh = paramiko.SSHClient() # Create SSH Object
# Allow connection not in know_hosts Host in file
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# Connect to the server
ssh.connect(hostname='192.168.2.103', port=22, username='root', password='123456')
stdin, stdout, stderr = ssh.exec_command('ls') # Execute a command
result = stdout.read() # Get command results
print (str(result,encoding='utf-8'))
ssh.close() # Close the connection
There is an transport variable in SSHClient (), which is used to get the connection. We can also get the transport variable separately and then perform the connection operation
import paramiko
transport = paramiko.Transport(('192.168.2.103', 22))
transport.connect(username='root', password='123456')
ssh = paramiko.SSHClient()
ssh._transport = transport
stdin, stdout, stderr = ssh.exec_command('df')
print (str(stdout.read(),encoding='utf-8'))
transport.close()
Upload, download and command execution with transport:
#coding:utf-8
import paramiko
import uuid
class SSHConnection(object):
def __init__(self, host='192.168.2.103', port=22, username='root',pwd='123456'):
self.host = host
self.port = port
self.username = username
self.pwd = pwd
self.__k = None
def connect(self):
transport = paramiko.Transport((self.host,self.port))
transport.connect(username=self.username,password=self.pwd)
self.__transport = transport
def close(self):
self.__transport.close()
def upload(self,local_path,target_path):
# Connect, upload
# file_name = self.create_file()
sftp = paramiko.SFTPClient.from_transport(self.__transport)
# Will location.py Upload to server /tmp/test.py
sftp.put(local_path, target_path)
def download(self,remote_path,local_path):
sftp = paramiko.SFTPClient.from_transport(self.__transport)
sftp.get(remote_path,local_path)
def cmd(self, command):
ssh = paramiko.SSHClient()
ssh._transport = self.__transport
# Execute a command
stdin, stdout, stderr = ssh.exec_command(command)
# Get command results
result = stdout.read()
print (str(result,encoding='utf-8'))
return result
ssh = SSHConnection()
ssh.connect()
ssh.cmd("ls")
ssh.upload('s1.py','/tmp/ks77.py')
ssh.download('/tmp/test.py','kkkk',)
ssh.cmd("df")
ssh.close()