Python Forum
Python error handling Paramiko
Thread Rating:
  • 1 Vote(s) - 4 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Python error handling Paramiko
#1
Hello,

I am writing a Python script, using Paramiko, to ssh to servers one by one to test connectivity. The issue I am having is, if one of the server is unavailable, I get a stack trace and my program stops running there on. How do I just report something like "connection refused" and move on to another host please?


import logging
import sys
import getpass
import paramiko
from paramiko import client
import threading, paramiko

username = raw_input("Username: ")
password = getpass.getpass("Password: ")


class ssh:
        client = None
        shell = None
        transport = None

        def __init__(self, address):
                
                print("Connecting to server : " + address + ".")
                
                self.client = paramiko.client.SSHClient()
                self.client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
                self.client.connect(address, username=username, password=password, look_for_keys=False)
                


        def sendCommand(self, command):
                if(self.client):
                        stdin, stdout, stderr = self.client.exec_command(command)
                        while not stdout.channel.exit_status_ready():
                                #Print data whena available
                                if stdout.channel.recv_ready():
                                        alldata =  stdout.channel.recv(1024)
                                        prevdata = b"1"
                                        while prevdata:
                                                prevdata = stdout.channel.recv(1024)
                                                alldata += prevdata
                                        print(str(alldata))
                else:
                        print("Connection not opened.")

connection = ssh("host1")
connection.sendCommand("uptime")
connection = ssh("host2")
connection.sendCommand("uptime")
connection = ssh("host3")
Reply
#2
If you're getting an error, and want to handle it safely, then you're looking for exception handling: https://docs.python.org/3/tutorial/errors.html

>>> def i_always_fail():
...   print("here we go!")
...   raise Exception("dead")
...
>>> i_always_fail()
here we go!
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in i_always_fail
Exception: dead
>>> try:
...   i_always_fail()
... except Exception as err:
...   print("Error happened: {}".format(err))
...
here we go!
Error happened: dead
Reply
#3
I think you'd better to use multiple threads. Here is an example:

# _*_ coding:utf-8 _*_
import time
import os
import paramiko
import threading
import datetime
import traceback
import re
current_path = os.getcwd()

# customize the following path

# the content of host list file should be:
# officename swname swip username password
# eg: marvin huawei 10.0.0.7 jack 123456
host_list_path = current_path + '/sw.txt'

# puts your commands to this file one by one line
command_list_path = current_path + '/command.txt'

# Don't add backslash at the end of path.
log_path = '/home/seven/log'

# get current time
now = datetime.datetime.now()

# get thread lock
thread = threading.Lock()

# thread list
threads = []

# success hosts list
success_hosts = []

# failed hosts list
fail_hosts = []
#Use for loop to telnet into each routers and execute commands
class Bakconf(threading.Thread):
	def __init__(self, swname, host, username, password, port, day_dir, screen_command):
		threading.Thread.__init__(self)
		self.swname = swname
		self.host = host
		self.username = username
		self.password = password
		self.port = port
		self.log_dir = day_dir
		self.screen_command = screen_command
	def run(self):
		try:
			paramiko.util.log_to_file('ssh.log')
			ssh_client = paramiko.SSHClient()
			ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

			print("Connecting to server %s" % self.host)
			ssh_client.connect(self.host, self.port, self.username, self.password, allow_agent = False, look_for_keys = False, timeout=10)
			print("Successfully connected to server %s." % self.host)
			chan = ssh_client.invoke_shell()
			time.sleep(2)

			if chan.send_ready():
				chan.send(self.screen_command+"\n")
			else:
				raise("Channel not ready!")

			sleep_time = 10

			# execute commands in commands file.
			for command in open(command_list_path, 'r').read().splitlines():
				chan.send(command+"\n")
				print("%s is running. Sleep for %d seconds!" % (self.host, sleep_time))
				time.sleep(sleep_time)

			# write output to log file.
			filename = self.log_dir + "/%s:%i-%.2i-%.2i-%.2i:%.2i:%.2i.log" % (self.swname, now.year, now.month, now.day, now.hour, now.minute, now.second)
			with open(filename,"ab+") as fp:
				resp = chan.recv(9999999)
				fp.write(resp)

			print("Host %s was exported Successfully!" % self.host)
			chan.send('quit\n')
			ssh_client.close()
			success_hosts.append(self.host)
		except:
			fail_hosts.append(self.host)
			print("Can't connect to %s" % self.host)
			print("port=%s, username=%s, password=%s" % (self.port, self.username, self.password))
			traceback.print_exc()
			print("Thread exit!\n")
			return

def main():
	for line in open(host_list_path, 'r').read().splitlines():
		if line:
			try:
				officename, swname, swip, username, password, screen_command = re.split(',\s?', line)
			except:
				print("\nThe style of host list file is incorrect.\n")292.82
				return
			office_dir = log_path + "/" + officename
			if not os.path.exists(office_dir):
				os.makedirs(office_dir)

			day_dir = office_dir + "/%i-%.2i-%i" % (now.year, now.month, now.day)
			if not os.path.exists(day_dir):
				os.mkdir(day_dir)
			bakconf_thread = Bakconf(swname, swip, username, password, 22, day_dir, screen_command)
			bakconf_thread.start()
			threads.append(bakconf_thread)
	for t in threads:
		t.join()
	print("Finish!\nSucceeded hosts: %s\nFailed hosts: %s" % (success_hosts, fail_hosts))
if __name__=="__main__":
	main()

Better not to use 'exec_command' command.
SSH client will be closed if this command is executed.
And you have to reconnect to the server if you want to execute other commands. So:
'chan = ssh_client.invoke_shell()' is a good choice.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Paramiko Server -- Exception (server): Error reading SSH protocol banner ujlain 3 4,277 Jul-24-2023, 06:52 AM
Last Post: Gribouillis
  Paramiko resource shortage error michu7 0 2,800 Apr-10-2020, 04:04 PM
Last Post: michu7
  Python Paramiko, continuing the interaction for a command in interactive shell aditya_g01 0 8,685 Mar-13-2018, 04:51 AM
Last Post: aditya_g01
  How to keep paramiko ssh session open after loggin in using python? MikeHill 3 13,444 Aug-15-2017, 06:55 PM
Last Post: nilamo

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020