简体   繁体   English

解决 ssh 不转发信号的问题

[英]Work around ssh does not forward signal

How can I work around the problem that ssh does not forward the SIGTERM signal?如何解决ssh不转发SIGTERM信号的问题?

I want print-signal.py to terminate of the ssh root@localhost process terminates:我希望print-signal.py终止ssh root@localhost进程终止:

ssh root@localhost /root/print-signal.py

Unfortunately only the ssh process itself gets the signal, not the remote command ( print-signal.py ).不幸的是,只有 ssh 进程本身获得信号,而不是远程命令( print-signal.py )。 The remote command does not terminate :-(远程命令不会终止:-(

Since openssh does not forward the SIGTERM to the remote command, I am searching for a work-around.由于 openssh 不会将SIGTERM转发到远程命令,因此我正在寻找解决方法。

How to terminate print-signal.py if ssh root@localhost ... terminates?如果ssh root@localhost ... 终止,如何终止print-signal.py

This is a follow-up question to: Forwarding SIGTERM over ssh这是一个后续问题: 通过 ssh 转发 SIGTERM

Disclaimer: the answer below is not for SIGTERM, but SIGINT.免责声明:下面的答案不是针对 SIGTERM,而是针对 SIGINT。 This is not an answer to the question due to oversight.由于疏忽,这不是问题的答案。

The problem you are observing is due to a missing tty which should be in control of the process you try to run.您观察到的问题是由于缺少 tty,它应该控制您尝试运行的进程。 If there is no tty available, ssh is unable to send the signals to the process.如果没有可用的 tty,ssh 将无法向进程发送信号。 When you use the option -t to the ssh command, it will force pseudo-terminal allocation which makes it possible to send signals over ssh :当您对ssh命令使用选项-t ,它将强制伪终端分配,这使得通过 ssh 发送信号成为可能:

ssh -t root@localhost /root/print-signal.py

man ssh -t Force pseudo-terminal allocation. man ssh -t强制伪终端分配。 This can be used to execute arbitrary screen-based programs on a remote machine, which can be very useful, eg when implementing menu services.这可用于在远程机器上执行任意基于屏幕的程序,这非常有用,例如在实现菜单服务时。 Multiple -t options force tty allocation, even if ssh has no local tty.多个-t选项强制 tty 分配,即使 ssh 没有本地 tty。

A very nice explanation how and why is given by Giles on unix.stackexchange . Giles 在 unix.stackexchange 上给出了一个非常好的解释。

Here you see how it works :在这里你可以看到它是如何工作的:

[terminal 1]% ssh server ./print_signal.py

On an other terminal you see then that print_signal.py is running on PID=26992 under the ssh with PID=26991 without a tty ( username@notty )上看到然后一个其他终端,其print_signal.py上运行PID=26992sshPID=26991无TTY( username@notty

[terminal 2]% ssh server ps -f                                                                                                                                                                                                            
UID        PID  PPID  C STIME TTY          TIME CMD
username 26991 26989  0 17:06 ?        00:00:00 sshd: username@notty
username 26992 26991  0 17:06 ?        00:00:00 python ./print_signal.py
username 27347 27345  0 17:07 ?        00:00:00 sshd: username@notty
username 27348 27347  0 17:07 ?        00:00:00 ps -f

After killing the ssh process with kill or CTRL - C , the process is still active but runs now under /sbin/init ( PPID=1 )使用 kill 或CTRL - C杀死 ssh 进程后,该进程仍处于活动状态,但现在在/sbin/init ( PPID=1 ) 下运行

[terminal 2]% ssh server ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
username 26992     1  0 17:06 ?        00:00:00 python ./print_signal.py
username 27453 27451  0 17:08 ?        00:00:00 sshd: username@notty
username 27454 27453  5 17:08 ?        00:00:00 ps -f

using the -t flag nicely kills the process on the other side:使用-t标志可以很好地终止另一端的进程:

[terminal 1]% ssh -t server ./print_signal.py

On an other terminal you see then that print_signal.py is running on PID=39277 under the ssh with PID=39276 bound to a tty ( username@pts/10 )上看到然后一个其他终端,其print_signal.py上运行PID=39277sshPID=39276绑定到一个tty( username@pts/10

[terminal 2]% ssh server ps -U username -f
UID        PID  PPID  C STIME TTY          TIME CMD
username 39276 39274  0 17:22 ?        00:00:00 sshd: username@pts/10
username 39277 39276  1 17:22 pts/10   00:00:00 python ./print_signal.py
username 39317 39314  0 17:22 ?        00:00:00 sshd: username@notty
username 39318 39317  5 17:22 ?        00:00:00 ps -U username -f

After killing the ssh process杀死ssh进程后

[terminal 1]% ssh -t server ./print_signal.py
My PID: 39277
^CCaught signal SIGINT (2), exiting.
Connection to server closed

The process is now clearly terminated on the other server该进程现在清楚地在另一台服务器上终止

[terminal 2]% ssh server ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
username 39768 39765  0 17:26 ?        00:00:00 sshd: username@notty
username 39769 39768  6 17:26 ?        00:00:00 ps -U username -f

I have just been having exactly this problem.我刚刚遇到了这个问题。 While I haven't figured out the exact cause, what happens when ssh is terminated is that your process is re-parented to init .虽然我还没有弄清楚确切的原因,但当ssh终止时会发生什么是您的进程重新父级为init You can tell your process to ask for a signal when it's parent dies instead using prctl .您可以告诉您的进程在其父进程死亡时请求一个信号,而不是使用prctl

If you use python-prctl , put the following early on in /root/print-signal.py如果您使用python-prctl ,请将以下内容尽早放入/root/print-signal.py

import signal
import prctl

prctl.set_pdeathsig(signal.SIGTERM)

You could write a wrapper which terminates if the parent process is the init process:如果父进程是 init 进程,您可以编写一个终止的包装器:

ssh root@localhost terminate-command-if-parent-is-lost print-signal.py

The tool terminate-command-if-parent-is-lost needs to do this:工具terminate-command-if-parent-is-lost需要这样做:

Start the argv as subprocess (in this example print-signal.py ).启动 argv 作为子print-signal.py (在本例中为print-signal.py )。 Then it checks every second the status of its parent pid (in Python os.getppid() ).然后它每秒检查其父 pid 的状态(在 Python os.getppid() )。

If ppid is 1 (the init process), then the print-signal.py process has lost its parent.如果 ppid 为 1(init 进程),则 print-signal.py 进程丢失了它的父进程。 This means "ssh root@localhost ..." was terminated (or connection was closed).这意味着“ssh root@localhost ...”已终止(或连接已关闭)。

Now terminate-command-if-parent-is-lost terminates the subprocess.现在terminate-command-if-parent-is-lost终止子进程。

The shell can easily help you for such problem, if it supports some builtin variable( $! ).如果 shell 支持某些内置变量( $! ),它可以轻松地帮助您解决此类问题。 Here is a basic shell solution by replacing your command by a very long sleep.这是一个基本的 shell 解决方案,通过很长的睡眠替换您的命令。

ssh server '(sleep 100000 & (MID=$!; A=n; while [ "$A" != y ];do echo "i am process $$ want kill "$MID" y/n?"; read A; done; kill -TERM $MID))'

The script sent in the command is running on the remote host.命令中发送的脚本正在远程主机上运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM