1

I need a way to capture exit status from a command run through SSH. Would like the exit status to end up within a variable. I cannot seem to get it working though.

Command would be something simple like:

os.system("ssh -qt hostname 'sudo yum list updates --security > /tmp/yum_update_packagelist.txt';echo $?")

Anyone have an idea? Everything I've tried has either not worked at all, or ended up giving me the exit status of the ssh command, not the underlying command.

2 Answers2

0

You probably want to use the Fabric api instead of directly calling the ssh executable.

From there, check out Can I catch error codes when using Fabric to run() calls in a remote shell?

Community
  • 1
  • 1
Jeff Ferland
  • 17,832
  • 7
  • 46
  • 76
0

You probably want to use an SSH library like paramiko (or spur, Fabric, etc.… just google/PyPI/SO-search for "Python SSH" to see all the options and pick the one that best matches your use case). There are demos included with paramiko that do exactly what you want to do.

If you insist on scripting the command-line ssh tool, you (a) almost certainly want to use subprocess instead of os.system (as the os.system docs explicitly say), and (b) will need to do some bash-scripting (assuming the remote side is running bash) to pass the value back to you (e.g., wrap it in a one-liner script that prints the exit status on stderr).

If you just want to know why your existing code doesn't work, let's take a look at it:

os.system("ssh -qt hostname 'sudo yum list updates --security > /tmp/yum_update_packagelist.txt';echo $?")

First, you're running an ssh command, then a separate echo $? command, which will echo the exit status of ssh. If you wanted to echo the status of the sudo, you need to get the semicolon into the ssh command. (And if you wanted the status of the yum, inside the sudo.)

Second, os.system doesn't look at what gets printed to stdout anyway. As the docs clearly say, "the return value is the exit status of the process". So, you're getting back the exit status of the echo command, which is pretty much guaranteed to be 0.'

So, to make this work, you'd need to get the echo into the right place, and then read the stdout by using subprocess.check_output or similar instead of os.system, and then parse that output to read the last line. If you do all that, it should work. But again, you shouldn't do all that; just use paramiko or another SSH library.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • You're wrong about the echo. It's in the right place. It executes the yum command, then echo's the status of the yum command, since it echo's whatever is immediately preceding it on the remote system. I verified that multiple times during my trial and error guessing. The issue was never that I wasn't getting the right exit code, it was that I couldn't find a way to get that exit code into a variable on the local system. – Kris Griebe Apr 05 '13 at 01:39
  • Anywho, I decided to use the SSH module (uses the paramiko library as you suggested) to do this and have it working now. – Kris Griebe Apr 05 '13 at 01:40
  • No, the `echo $?` is not running on the remote system. You can see this by just changing it to, e.g., `echo $HOSTNAME`—it will print the hostname of your machine, not the remote system. The reason it seems to work is that in most cases, the exit status of `ssh` is the exit status of the remote command. But it's very important to understand the difference when you're using `ssh` and `sudo`; if you don't know what's part of what command, you are going to run into serious problems (possibly involving gaping security holes) at some point. – abarnert Apr 05 '13 at 02:01
  • My apologies, you're right, I pasted in the wrong syntax up above. Originally I had the echo enclosed within the ' ', which does exactly what I was saying it does. Didn't realize I pasted in the wrong line (the line above was another thing I'd tried to see what output it would give me). – Kris Griebe Apr 05 '13 at 02:21