python exception handling is not working with fabric.api - python

I am working on a code so that it can handle the error from fabric.local, but some how it always abort with the error and never go into except block.
Here is my code, hopefully can get some idea from you guys
This snippet is trying to get Vagrant ssh port, if the vagrant is not up, bring it up
def findsshport():
with settings(warn_only=True):
try:
print 'greping port'
return (local('vagrant ssh-config {} | grep Port'.format(env.vmId), capture=True))
except:
print 'vagrant not up'
with lcd('%s' % (buildfolder)):
local('vagrant up ext4')
return (local('vagrant ssh-config {} | grep Port'.format(env.vmId), capture=True))
env.user = 'root'
sshPort = findsshport()
env.hosts = ['127.0.0.1:' + sshPort.split()[1]]
Error
[localhost] local: vagrant ssh-config 22921a7 | grep Port
Warning: local() encountered an error (return code 1) while executing 'vagrant ssh-config 22921a7 | grep Port'
Traceback (most recent call last):
File "/home/testing/local/lib/python2.7/site-packages/test123/fabriclogin.py", line 114, in sshlogin
env.hosts = ['127.0.0.1:' + sshPort.split()[1]]
AttributeError: 'NoneType' object has no attribute 'split'
UPDATE
Similar Question and Answer
Can I catch error codes when using Fabric to run() calls in a remote shell?

It seems like it's just a warning from fabric. My understand if you encounter an error on ssh, it doesn't "translate" into a Python error, that's why the exception block doesn't work. Please provide error trace for further analysis.

Martin is correct, that was a warning from fabric.api.local and python exception handling will not treat it as an error. Instead, the error that I seen was from another part of code which the above snippet had returned something invalid.
Instead of using try and except, if else is used with return_code which checking the command exit status.
port = local('vagrant ssh-config {} | grep Port'.format(env.vmId), capture=True)
if port.return_code == 0:
return port
else:
with lcd('%s' % (buildfolder)):
local('vagrant up {}'.format(env.vmId), capture=True)
return (local('vagrant ssh-config {} | grep Port'.format(env.vmId), capture=True))

Your problem is probably here.
with settings(warn_only=True)
Remove this line, and your local call will raise exceptions if the command exits with a non-zero return code.
def task_name():
with settings(warn_only=True):
try:
local("invalid_command")
except:
print("This will never print!")
Lets compare that to;
def task_name():
try:
local("invalid_command")
except:
print("This will print")

Related

Python Fabric return value on remote run command

I'm using run command from python fabric to execute a script remotely.
C = fabric.Connection('ip', user='user', connect_kwargs={"password": "password"})
try:
r = C.run('python3 ~/script.py')
if r:
print('{} SUCCESS'.format(C.host))
break
else:
print('{} ERROR'.format(C.host))
break
except:
print('{} ERROR'.format(C.host))
My script.py is:
def download_file(url, filename):
try:
response = requests.get(url)
# Open file and write the content
with open(filename, 'wb') as file:
# A chunk of 128 bytes
for chunk in response:
file.write(chunk)
return 1
except requests.exceptions.RequestException as e:
return 0
download_file(url,filename)
When I execute a run command, is there a way to see, which value was returned in my function, 1 or 0?
Thank you!
According to the Fabric 2.x docs, results are by default captured and made available under stdout and stderr attributes on a result: http://docs.fabfile.org/en/2.0/getting-started.html#run-commands-via-connections-and-run
r = C.run('python3 ~/script.py')
print(r.stdout)
The run command returns a Result object, which has the following properties (amongst others):
stdout - the standard out
stderr - the standard error
exited - the exit code for the program
ok - exited == 0
return_code - an alias for exited
so you need to check the exited/return_code property.
However, your script does not exit with the return code of the function. For this you need to sys.exit with that value, so altering the download_file to:
sys.exit(download_file(url))
would get you the return code from the download_file function. You would need to import sys on the script to ensure you have the sys module available.
When the program fails with a non-zero exit code, an UnexpectedExit exception is thrown. In order to get the exit code in that case you can either (a) capture the exception, or (b) pass in the parameter warn=True to the run command, so the run command would look like:
r = C.run('python3 ~/script.py', warn=True)

Executing DevCon CMD command from python

I want to restart driver with DevCon from python script. It works from command line with this command:
devcon restart \"sd0007322081041363_kcanv\"
I tried this:
os.system("devcon restart \"sd0007322081041363_kcanv\"")
with result:
'devcon' is not recognized as an internal or external command
I read that os.system is obsolete and i need to use subprocess.check_output so i try this:
subprocess.check_output(['devcon', 'restart', '"sd0007322081041363_kcanv"'])
with result:
WindowsError:[Error 2] The system cannot find the file specified
and this:
subprocess.check_output('devcon restart "sd0007322081041363_kcanv"', shell=True)
with result:
subprocess.CalledProcessError: Command 'devcon restart "sd0007322081041363_kcanv"' returned non-zero exit status 1
and this:
subprocess.Popen("devcon restart \"sd0007322081041363_kcanv\"", shell=True, stdout=subprocess.PIPE).stdout.read()
result:
'devcon' is not recognized as an internal or external command
and this:
try:
subprocess.check_output('devcon disable "sd0007322081041363_kcanv" /f',shell=True,stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output))
with result:
RuntimeError: command 'devcon disable "sd0007322081041363_kcanv" /f' return with errpr (cpde 1): 'devcon' is not recognized as an internal or external command, operable program or batch file
devcon.exe is under Windows/System32 and it is set in system path.
I know that this can be duplicate question but I have tried many solution on stackoverflow but i van't resolve this issue.
Finally, I came up with a solution. I tried many things but this is what works for me:
copy devcon.exe from C:\Windows\System32 and put it to C:\Windows\SysWOW64.
my code:
try:
subprocess.check_output('C:\\Windows\\SysWOW64\\devcon.exe restart "sd0007322081041363_kcanv" /f',shell=True,stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output))

Catch an error from command line Python

I need to catch an error from command line without print error message on the screen. When this occurs I need to give another command to run.
This is what I do now:
hyst_cmd = "si viewhistory ..."
process = subprocess.Popen(hyst_cmd, stdout=subprocess.PIPE)
hyst = process.stdout.read().splitlines()
When I do this for some projects I receive an error message, on the screen.
Sorry for my english!
According to the official document, the most common exception for Popen in subprocess is OSError.
To catch the error, you can simply try the following approach:
hyst_cmd = "si viewhistory ..."
try:
process = subprocess.Popen(hyst_cmd, stdout=subprocess.PIPE)
hyst = process.stdout.read().splitlines()
except OSError:
<write_log_file or other action.>
For more information, you can check the link below:
Subprocess Exception

Socket function getting error

Im trying to do a socket.gethostbyname from a list of subdomains concatenated with an argument value but am getting an error. Im not sure if the loop isnt working correctly and the first try is just not a valid subdomain+domain. or if it just isnt working at all?
ERROR
Traceback (most recent call last):
File "./attack2.py", line 40, in <module>
print subcheck(returned_list, arguments['--domain'])
File "./attack2.py", line 31, in subcheck
socket.gethostbyname(sub + domain)
socket.gaierror: [Errno -2] Name or service not known
CODE
#!/usr/bin/python
"""
Description:
Basic Domain bruteforcer
Usage:
attack2.py (-f <file>) (-d <domain>) [-t 10] [-v]
attack2.py -h | --help
Arguments:
-f --file File to read potential Sub-domains from. (Required)
-d --domain Domain to bruteforce. (Required)
Options:
-h --help Show this screen.
-p --proxy Proxy address and port. [default: http://127.0.0.1:8080] (Optional)
-t --thread Thread count. (Optional)
-v --verbose Turn debug on. (Optional)
"""
import socket
from docopt import docopt
def fread(dwords):
flist = open(dwords).readlines()
return [s.replace('\n', '.') for s in flist]
def subcheck(subdomain, domain):
for sub in subdomain:
socket.gethostbyname(sub + domain)
return output
if __name__ == "__main__":
arguments = docopt(__doc__, version='0.1a')
print arguments
print fread(arguments['--file'])
returned_list = fread(arguments['--file'])
print subcheck(returned_list, arguments['--domain'])
NEW def subcheck code
def subcheck(subdomain, domain):
for sub in subdomain:
try:
#print "%s %d" % (sub+domain,len(sub+domain))
print socket.gethostbyname(sub + domain)
except:
print "Some error"
NEW OUTPUT
173.194.34.150
173.194.34.137
Some error
Some error
None
domain.google.com and stuff.google.com are invalid domains. Getting rid of those will fix the problem.
None is returned because you aren't returning anything in your subcheck function. So when you invoke it like this:
print subcheck(returned_list, arguments['--domain'])
it will be forced to return, and print None. Remove the print in front of it and you won't see None.
"[Errno -2] Name or service not known" sounds to me like your program cannot reach a DNS server. Can you resolve the names in some other way? e.g. using `dig'. I think if socket.gethostbyname cannot resolve the name, it returns a different error; when I try it, I get: "No address associated with hostname".

Python debug print the command

Folks
I am not very up with Python but have inherited a load of Python scripts
One of which is given me a issue in that I am not 100% sure what one line is running
What I need to do is print out the command line and its variables.
The line in question is
ldapModify(userdn, mods, uri=uri)
What I am hoping to see is something like
/usr/bin/ldapmodify xxxx cn=......
Can any kind soul help.
The Python ldap lib doesn't call on the ldap command line client, it binds directly to the underlying system ldap lib.
If what you want is to know the values of the args passed to ldapModify, it's quite simple: print them to sys.stderr :
import sys
try:
ldapModify(userdn,mods,uri=uri)
except Exception, e:
print >> sys.stderr, "oops, ldapModify failed with '%s'" % e
print >> sys.stderr, "userdns : '%s' - uri : '%s' - mods : '%s'" % (userdns, uri, mods)
# and reraise the error so you get the whole traceback
raise
Before the line in question, you could place a call to python's interactive debugger. Then you can print out the variables in question:
import pdb
pdb.set_trace()
ldapModify(userdn, mods, uri=uri)
At the (pdb) prompt you can print out the value of any or all of the variables.
Here's a link about the debugger.

Categories