Paramiko: Process dies, if it is run via paramiko ssh session and with “&” in the end

Created on 18 Mar 2015  ·  4Comments  ·  Source: paramiko/paramiko

I'm fighting with problem from question http://stackoverflow.com/questions/29105029/process-dies-if-it-is-run-via-paramiko-ssh-session-and-with-in-the-end about 2 days.
Now I think that problem can be in paramiko, because same command work normally in regular ssh

My paramiko version 1.15.2

Most helpful comment

long story short:
not a paramiko issue. your remote proc is just terminated because you end your ssh channel.

detailed answer:
With & you make your remote command exit instantly. The remote sshd will therefore likely (depends on implementation, but openssh does) kill all processes that were started from your command invocation. In your case, you just spawn a new process nohup tcpdump which will instantly return due to & at the end. The channel.recv_exit_status() will only block until the exit code for the & ooperation is ready which instantly is. Your code then just terminates, terminating your ssh session which will make the remote sshd kill the spawned nohup tcpdump proc. That why you end up with no tcpdump process.

Here's what you can do:

Since exec_command is going to spawn a new thread for your command, you can just leave it open and proceed with other tasks. But make sure to empty buffers every now and then (for verbose remote commands) to prevent paramiko from stalling.

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, username=login, password=password)
transport = ssh.get_transport()
channel_tcpdump = transport.open_session()
channel_tcpdump.get_pty()
channel_tcpdump.set_combine_stderr(True)

cmd = "tcpdump -i eth1  port 443 -w /tmp/dump20150317183305940107.pcap"        # command will never exit
channel_tcpdump.exec_command(cmd)  # will return instantly due to new thread being spawned.
# do something else
time.sleep(15)      # wait 15 seconds
_,stdout,_ = ssh.exec_command("pgrep tcpdump") # or explicitly pkill tcpdump
print stdout.read()     # other command, different shell
channel_tcpdump.close()     # close channel and let remote side terminate your proc.
time.sleep(10)

All 4 comments

long story short:
not a paramiko issue. your remote proc is just terminated because you end your ssh channel.

detailed answer:
With & you make your remote command exit instantly. The remote sshd will therefore likely (depends on implementation, but openssh does) kill all processes that were started from your command invocation. In your case, you just spawn a new process nohup tcpdump which will instantly return due to & at the end. The channel.recv_exit_status() will only block until the exit code for the & ooperation is ready which instantly is. Your code then just terminates, terminating your ssh session which will make the remote sshd kill the spawned nohup tcpdump proc. That why you end up with no tcpdump process.

Here's what you can do:

Since exec_command is going to spawn a new thread for your command, you can just leave it open and proceed with other tasks. But make sure to empty buffers every now and then (for verbose remote commands) to prevent paramiko from stalling.

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, username=login, password=password)
transport = ssh.get_transport()
channel_tcpdump = transport.open_session()
channel_tcpdump.get_pty()
channel_tcpdump.set_combine_stderr(True)

cmd = "tcpdump -i eth1  port 443 -w /tmp/dump20150317183305940107.pcap"        # command will never exit
channel_tcpdump.exec_command(cmd)  # will return instantly due to new thread being spawned.
# do something else
time.sleep(15)      # wait 15 seconds
_,stdout,_ = ssh.exec_command("pgrep tcpdump") # or explicitly pkill tcpdump
print stdout.read()     # other command, different shell
channel_tcpdump.close()     # close channel and let remote side terminate your proc.
time.sleep(10)

Hi @bitprophet
I have to write a question here, because I have a similar problem, and the method above cannot be solved.

There is a script on the remote server(10.201.143.183). The script a.sh reads as follows:
#
$ cat a.sh

#! / bin/bash
sleep 2
nohup /tmp/b.sh >> /tmp/a.log 2>>/tmp/a.log &

The script b.sh
cat b.sh

echo "aaa"
sleep 1
echo "bbb"
sleep 1
echo "cccc"

My python script is as follows:

import paramiko


def SSHCommand(hostname, username, password, command, timeout=90, get_pty=True, look_for_keys=True):
    '''
    连接远程服务器执行shell命令
    :param hostname: 127.0.0.1
    :param username: root
    :param command: 'ls;pwd;'
    :param timeout: 超时时间
    :return:
    '''
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    try:
        ssh.connect(hostname=hostname, port=22, username=username, password=password, timeout=8, look_for_keys=look_for_keys,)
        stdin, stdout, stderr = ssh.exec_command(command=command, timeout=timeout, get_pty=get_pty)
        ssh_result = {
            'output': stdout.readlines(),
            'IP': hostname,
            'msg': 1,
            'error': stderr.readlines(),
        }
        ssh.close()
    except Exception as e:
        ssh_result = {
            'output': 0,
            'IP': hostname,
            'msg': 0,
            'error': [str(e)],
        }
        ssh.close()
    return ssh_result


a = SSHCommand('10.201.143.183', 'root', 'rootroot', 'bash /tmp/a.sh')
print a

The b.sh script is not executed in the a.sh script on the remote server.Because/tmp/a.log has no log output.

if use command:
$ ssh [email protected] "/tmp/a.sh "
The b.sh script can be executed normally, and there is a log display in the /tmp/a.log file

I have found that it is normal to add the sleep 2 command after the nohup command.

@zhou-mfk
set
get_pty = False
and use
nohup /tmp/b.sh >> /tmp/a.log 2>>/tmp/a.log &
It works well for me.

Was this page helpful?
0 / 5 - 0 ratings