Python: pysftp exception handling - python

I am using pysftp with Python 3.7 to setup an SFTP client script.
My code (simplified and minimal):
import pysftp
import sys
# Variables
destination_dir = 'BOGUS_DIR'
server = 'myserver.mydomain.com'
user = 'my_user'
key = 'my_key'
port = 22
# cnopts
mycnopts = pysftp.CnOpts()
mycnopts.log = True
mycnopts.compression = True
mycnopts.ciphers = None
mycnopts.hostkeys = None
try:
with pysftp.Connection(server, username=user, private_key=key, port=port, cnopts=mycnopts) as sftp:
try:
with sftp.cd(destination_dir):
print("OK cd worked")
except:
print("NOT OK cd failed")
e = sys.exc_info()
print("Exception: {0}".format(e))
if sftp.isdir(destination_dir):
print("OK isdir")
else:
print("NOT OK isdir")
except:
print("Connection failure.")
e = sys.exc_info()
print("Exception: {0}".format(e))
The output is: OK cd worked
But I know for a fact that BOGUS_DIR does not exist. It is like pysftp does not raise the exception on cd(), or I am catching it wrong (hence my python code is not properly done).
Same for isdir(), whatever I put as parameter, it always returns True even if the directory does not exist.
If I change my connection parameters for something wrong, I do catch the connection failure exception.
Is pyftp processing exceptions wrong, or is my code at fault here? Should I not trust pysftp and use Paramiko directly?

If directory is not exist you getting an error from remote shell where you trying to run the command. In this code you trying to catch the exception that can be raised only by sftp. Maybe, you should check the status code that should be returned by sftp module after each executed shell command

Ok I figured it out, I think.
sftp.cd() does not raise an exception if the directory does not exist. Only operations on the bad directory do. So if I modify my code like this:
....
try:
with sftp.cd(destination_dir):
sftp.listdir()
print("OK ce worked")
except:
print("NOT OK cd failed")
e = sys.exc_info()
print("Exception: {0}".format(e))
....
This way I get an exception since sftp.listdir() cannot work with an inexistent directory.
Almost like sftp.cd does not do anything other than set the value of the current directory, without actually doing anything with it.

Related

How to check if the created file using Paramiko exec_command exists

I'm trying to open a file which got created as part of the Paramiko exec_command. The file gets created, but when I check if the file exists, it always returns false. How do I check if the file exists and then open the file for reading?
The code written is:
ip = '10.30.2.104'
username = 'root'
password = 'docker'
def checkSSH(ip, username, password, retries=1):
ssh = SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.load_system_host_keys()
for x in range(retries):
try:
ssh.connect(ip, username=username, password=password, timeout=10)
return ssh
except (
paramiko.BadHostKeyException, paramiko.AuthenticationException, paramiko.SSHException, socket.error) as e:
print('Exception occured.. {0}'.format(e))
return False
hdl = checkSSH(ip, username, password)
cmd = 'ls > test.log'
hdl.exec_command(cmd)
a = os.path.exists('/root/test.log')
print(a) >>> if the file exists, this returns true as per the documentation but in this case, it always returns false.
First, you are not waiting for the command to complete.
For that see:
Wait to finish command executed with Python Paramiko
Once the command completes, you can retrieve its exit code using Channel.recv_exit_status():
How can you get the SSH return code using Paramiko?
If it returns 0, you know that everything went fine and no additional check is needed.
Anyway, if you want to check, use SFTP (SFTPClient.stat):
sftp = hdl.open_sftp()
try:
sftp.stat('/root/test.log')
print("exists")
except Exception as e:
print("something is wrong: " + e)
Though the execution of ls command seems strange to me.
If you want to retrieve the directory listing, use SFTP: SFTPClient.listdir_attr

Client connect issue with adding error handling

I am trying to connect to an account on Splunk via Python and Bash. I can connect to the website fine and it prints what I want it to, in the terminal, when I log in correctly. However when I use the wrong log in details, it prints a large error message saying 'login failed' that I want to try and condense to one line only.
This is what I am using to connect to Splunk:
service = client.connect(
host=splunk_config['host'],
port=splunk_config['port'],
username=splunk_config['username'],
password=splunk_config['password'])
I want to do something along the lines of:
if (service errors):
print ("Failed to connect")
else:
print ("Successfully connected")
Without the exception and guessing you're using splunklib I would imagine you need something like:
try:
service = client.connect(
host=splunk_config['host'],
port=splunk_config['port'],
username=splunk_config['username'],
password=splunk_config['password'])
print("Login succesfull")
except splunklib.binding.AuthenticationError as e:
print("Login failed")

try except not running except part

I have a short code that ftps a small file into a server.
session = ftplib.FTP("192.168.0.164", "admin", "admin")
file = open("path/test.txt", "rb")
try:
session.storbinary("STOR application/test.txt", file)
except:
print("failed")
else:
print("success!")
file.close()
In the above piece I changed the IP address to so it would fail (there is no 192.168.0.164 device) and it doesn't print failed like it's supposed to. In the terminal I get a
"connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond" error.
if I mistype the path, I also don't get a failed print on the terminal.
If I type in the correct IP the success part does work.
Am I using the try/except wrong?
UPDATE:
Current code looks like this:
file = open("path/test.txt", "rb")
try:
session = ftplib.FTP("192.168.0.161", "admin", "admin")
session.storbinary("STOR application/test.txt", file)
except:
print("Unable to reach host")
else:
print("success!")
session.quit()
finally:
print ("DONE!!")
file.close()
I figure the ftplib.all_errors will catch all errors (host unreachable, and file not found). It seems to catch the unable to reach host errors, but no file not found errors.
Am I using the try/except wrong?
Your syntax is correct, but Python is not actually reaching the try block at all.
When you call session = ftplib.FTP(host, ...) where host is unreachable, the code will stop in its tracks there. That's because FTP.__init__() greedily calls self.connect(). This will in turn call socket.create_connection(), which will not succeed for an unreachable host.
So, you'd need to modify to:
with open("path/test.txt", "rb") as file:
try:
session = ftplib.FTP("192.168.0.164", "admin", "admin")
session.storbinary("STOR application/test.txt", file)
except Exception as e:
print("failed")
print(e)
else:
print("success!")
finally:
session.quit()

Locale variable socket referenced before assignment

I know there are other posts that are similar to mine but i did not get anything useful from those posts so here i go.
I have this code that i use:
def startElection():
index = vesselList.index(getmyip())
if index >= (len(vesselList)-1):
neighbour = vesselList[0]
else:
neighbour = vesselList[index+1]
try:
socket = openconn(neighbour, destport, localip=None, localport=None, timeout = 5)
socket.send(iD)
socket.close()
except socket.error, exc:
print "Caught exception socket.error : %s" % exc
I get the error:
Exception (with type 'exceptions.UnboundLocalError'): local variable 'socket' referenced before assignment
I have tried changing the name of the socket. I have tried writing socket= None before the try method. Im not really sure why this is happening.
******** EDIT 1 ********
I have this code that is almost identical to the one i showed you guys first. This code below me works perfectly fine to run, no errors. When i uncomment the function call made to startElection() the code below me runs perfectly.
#Start the for loop to send the new word to all the vessels in our vesselList.
destport = 63166
for destHost in vesselList:
if destHost != getmyip(): #Obviously we wont be needing to send it to the vessel it was made in.
try:
soocket = openconn(destHost, destport, localip=None, localport=None, timeout = 5)
soocket.send(userMSG)
soocket.close()
except soocket.error, exc:
print "Caught exception socket.error : %s" % exc
You're using socket as a variable name and as a type.
The socket.error type is on the socket class. Because you've declared that socket is a variable, the runtime has probably created the local variable name with out a reference and then tried to use it to set-up the exception handler.
Change the name of the variable and the problem should go away.
In my situation was that the port number was wrongly defined. A quick change on that fixed my problem!

How to properly use try/except in Python

I have a function that returns the DB connection handler from MongoDB. I have various other functions that makes a call to the DB, I figure let's throw the connection handler into a function so I don't have to define it in every function.
Does this look right? I guess my question is, if it can't make a connection to the DB server, it will print both messages Could not connect to server and No hosts found How can I go about only printing "Could not connect to the server."
def mongodb_conn():
try:
conn = pymongo.MongoClient()
except pymongo.errors.ConnectionFailure, e:
print "Could not connect to server: %s" % e
return conn
def get_hosts()
try:
conn = mongodb_conn()
mongodb = conn.dbname.collection
b = []
hosts_obj = mongodb.find({'_id': 'PR'})
for x in hosts_obj:
print x
except:
print "No hosts found"
get_hosts()
Move your conn = mongodb_conn() call out of the try .. except handler, and test if None was returned:
def get_hosts()
conn = mongodb_conn()
if conn is None:
# no connection, exit early
return
try:
mongodb = conn.dbname.collection
b = []
hosts_obj = mongodb.find({'_id': 'PR'})
for x in hosts_obj:
print x
except:
print "No hosts found"
You should, at all cost, avoid using a blanket except however; you are catching everything now, including memory errors and keyboard interrupts, see Why is "except: pass" a bad programming practice?
Use specific exceptions only; you can use one except statement to catch multiple exception types:
except (AttributeError, pymongo.errors.OperationFailure):
or you can use multiple except statements handle different exceptions in different ways.
Limit the exception handler to just those parts of the code where the exception can be thrown. The for x in hosts_obj: loop for example is probably not going to throw an AttributeError exception, so it should probably not be part of the try block.
Note that you'll need to adjust your mongodb_conn() function to not try and use the conn local if it has never been set; you'll get an UnboundLocal error if you do:
def mongodb_conn():
try:
return pymongo.MongoClient()
except pymongo.errors.ConnectionFailure, e:
print "Could not connect to server: %s" % e
Now the function returns the connection if successful, None if the connection failed.
You can also check if the server is available
like this:
from pymongo.errors import ConnectionFailure
client = MongoClient()
try:
# The ismaster command is cheap and does not require auth.
client.admin.command('ismaster')
except ConnectionFailure:
print("Server not available")

Categories