I'm trying to use Paramiko to write a deployment script, and I'm having trouble with exit codes from the commands I run. I'm using code similar to that in this answer, but it's a little more complicated. Basically, from our dev boxes we have to go through a jump server, and from there to a series of production machines. Once there we have to switch to a system user (sudo su - systemuser) and then we can run commands.
The problem is that as I understand it I have 3 subshells - the ssh session, the nested ssh command and then the su subshell. I can't get Paramiko to give me back the exit code of the commands in the inner subshell - I guess the exit code it will eventually return will be that of the ssh command. I suspect this problem is not actually specific to Paramiko - does the SSH protocol even support this kind of usage?
I'm currently always executing:
(my command); echo "Process terminated with exit code $?"
and then parsing this out on the client, but it's pretty ugly - is there a nicer way?
To check the exit code we can simply print the $? special variable in bash. This variable will print the exit code of the last run command.
Checking Bash Exit Code Launch a terminal, and run any command. Check the value of the shell variable “$?” for the exit code. $ echo $? As the “date” command ran successfully, the exit code is 0.
Use signals to exit process from subshell This is the mechanism that allows you to exit a command line process by pressing ctrl-c. When you press ctrl-c in your terminal, an interrupt signal (SIGINT) is sent to the current process.
Extracting the elusive exit code To display the exit code for the last command you ran on the command line, use the following command: $ echo $? The displayed response contains no pomp or circumstance. It's simply a number.
I guess the exit code it will eventually return will be that of the ssh command. I suspect this problem is not actually specific to Paramiko - does the SSH protocol even support this kind of usage?
Yes, and no.
The exit status is always returned, but it may not be from where you think. Once you call invoke_shell()
, your remote process is a shell, probably bash. The exit_status
you receive will be the one from that shell, not any of the processes it ran. Paramiko (nor any ssh implementation) can ever return the exit status of your commands, because the exit statuses are never seen outside of that remote shell. It's up to you to determine what your exit status should be, and exit the shell with exit $EXIT_STATUS
(often exit $?
is enough)
If you can break up your commands, or wrap them in a script, then use the exec_command()
method, you will have access to the correct exit status directly.
Alternatively, you can use shell command exec
in the remote shell, and the shell's process will be replaced by the command called by exec, and its exit status will be returned.
All three of these methods will set the channel.exit_status
attribute as expected.
I'm having a problem where the man page for 'ssh' says that it returns the exit code of the process it runs, but I can't seem to get it to return a non-zero error code. From the ssh man page:
The session terminates when the command or shell on the remote machine
exits and all X11 and TCP/IP connections have been closed. The exit sta‐
tus of the remote program is returned as the exit status of ssh.
That doesn't seem to be true.
But I would try something like this and see what happens on your system.
% ssh localhost bash -c "exit 3" ; echo $?
0
When I run a similar command locally, bash returns an exit code.
% bash -c 'exit 3' ; echo $?
3
The double quotes will be removed before ssh seems the commands however. So let's try more quotes.
% ssh localhost bash -c "'exit 3'" ; echo $?
3
Bingo. The "exit 3" was turning into "exit" followed by an ignored word on the bash command line. So bash was running the command "exit".
Unfortunately for me, I think this whole answer is a digression from the original questions and doesn't contain enough merit as a question in its own right. So thanks everyone for helping me answer by secondary question (not related to the original question).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With