Paramiko 和 exec_command - 杀死远程进程?
我正在使用 Paramiko tail -f
远程服务器上的文件。
以前,我们通过 ssh -t 运行此命令,但事实证明这很不稳定,而且 -t 导致我们的远程调度系统出现问题。
我的问题是当脚本捕获到 SIGINT 时如何杀死 tail?
我的脚本(基于长-在 python paramiko 模块中运行 ssh 命令(以及如何结束它们))
#!/usr/bin/env python2
import paramiko
import select
client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect('someserver', username='victorhooi', password='blahblah')
transport = client.get_transport()
channel = transport.open_session()
channel.exec_command("tail -f /home/victorhooi/macbeth.txt")
while True:
try:
rl, wl, xl = select.select([channel],[],[],0.0)
if len(rl) > 0:
# Must be stdout
print channel.recv(1024)
except KeyboardInterrupt:
print("Caught control-C")
client.close()
channel.close()
exit(0)
脚本成功捕获我的 Ctrl-C 并结束。但是,它会使 tail -f
进程在远程系统上运行。
client.close() 和channel.close() 似乎都没有终止它。
我可以在 except 块中发出什么命令来杀死它?
远程服务器正在运行 Solaris 10。
I'm using Paramiko to tail -f
a file on a remote server.
Previously, we were running this via ssh -t
, but that proved flaky, and the -t
caused issues with our remote scheduling system.
My question is how to kill tail when the script catches a SIGINT?
My script (based on Long-running ssh commands in python paramiko module (and how to end them))
#!/usr/bin/env python2
import paramiko
import select
client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect('someserver', username='victorhooi', password='blahblah')
transport = client.get_transport()
channel = transport.open_session()
channel.exec_command("tail -f /home/victorhooi/macbeth.txt")
while True:
try:
rl, wl, xl = select.select([channel],[],[],0.0)
if len(rl) > 0:
# Must be stdout
print channel.recv(1024)
except KeyboardInterrupt:
print("Caught control-C")
client.close()
channel.close()
exit(0)
The script catches my Ctrl-C successfully, and ends. However, it leaves the tail -f
process running on the remote system,.
Neither client.close() nor channel.close() seem to terminate it.
What command can I issue in the except block to kill it?
The remote server is running Solaris 10.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
您应该使用 ssh keepalives...您遇到的问题是远程 shell 无法知道(默认情况下)您的 ssh 会话已被终止。 Keepalives 将使远程 shell 能够检测到您终止了会话
将 keepalive 值设置为您喜欢的最低值(甚至 1 秒)...几秒钟后,远程 shell 将看到 ssh 登录已终止,并将终止任何会话由它产生的进程。
You should use ssh keepalives... the problem you have is that the remote shell has no way of knowing (by default) that your ssh session was killed. Keepalives will enable the remote shell to detect that you killed the session
Set the keepalive value as low as you like (even 1 second)... after several seconds, the remote shell will see that the ssh login died, and it will terminate any processes that were spawned by it.
有一种方法可以做到这一点。它的工作方式就像在 shell 上一样。
选项 -t 打开一个伪 pty 来帮助 ssh 跟踪这个过程应该持续多长时间。同样的事情可以通过 pormiko
在execute_command(...)之前完成。这不会像使用channel.invoke_shell()那样打开shell,它只是请求这样一个伪接口来绑定所有进程。如果在远程计算机上发出 ps aux,也可以看到效果,该进程现在通过 ptxXY 接口连接到 sshd。
There is one way to do this. It works like on the shell
The option -t is opening a pseudo pty to help ssh to track how long this process should last. the same can be done via pormiko via
prior to execute_command(...). This will not open a shell like it does with channel.invoke_shell(), it just requests such a pseudo interface to tie all processes to. The effect can also be seen if ps aux is issued on the remote machine, the process is now attached to the sshd with a ptxXY interface.
我刚刚遇到这个问题,但无法最终发出 pkill 来关闭该进程。
更好的解决方案是将您正在运行的命令更改为:
这将允许您根据需要运行 tail 命令。一旦您向远程进程发送换行符,kill %1 就会执行并停止您后台运行的 tail 命令。 (供参考:%1 是一个作业规范,用于描述会话中第一个后台进程,即 tail 命令)
I just hit this issue and wasn't in a position to issue a pkill to close the process at the end.
A better solution is to change the command you are running to:
This will let you run your tail command for as long as you need. As soon as you send a newline to the remote process the kill %1 will execute and stop the tail command you backgrounded. (for reference: %1 is a jobspec and used to describe the first process that has been backgrounded in your session, ie the tail command)
以下是获取远程进程 ID 的方法:
以下是如何使用它(将
...
替换为原始问题中的位):Here's a way to obtain the remote process ID:
And here's how to use it (replace
...
with the bits in the original question):虽然不是最有效的方法,但这应该可行。 CTRL+C之后;在 KeyboardInterrupt 处理程序中,您可以像这样
exec_command("killall -u %s tail" % uname)
:这将杀死所有名为
tail
的打开进程。如果您打开了tail
并且不想关闭,这可能会导致问题,如果是这种情况,您可以grep
aps
,得到pid 并kill -9
它。首先,将 tail 设置为在跟随之前从文件末尾读取
n
行。将n
设置为一个唯一的数字,例如time.time()
,因为 tail 不关心该数字是否大于文件中的行数,即大数字来自time.time()
不应引起问题并且是唯一的。然后 grep 查找ps
中的唯一编号:While not the most efficient method, this should work. After you CTRL+C; In the KeyboardInterrupt handler you could
exec_command("killall -u %s tail" % uname)
like so:This would kill any open processes named
tail
. That may cause issues though if you havetail
s open that you dont want to close, if thats the case you couldgrep
aps
, get the pid andkill -9
it.First, set tail to read
n
lines from end of file before following. setn
to a unique nuber liketime.time()
, since tail doesn't care if that number is larger then the number of lines in the file, the large number fromtime.time()
shouldnt cause issues and will be unique. Then grep for that unique number in theps
:ssh -t 也有同样的问题。有一个名为 closer 的库 - 它通过 ssh 运行远程进程并自动为您关闭。一探究竟。
Had the same problem with
ssh -t
. There is a library called closer - it runs a remote process via ssh and closes automatically for you. Check it out.特别是对于“tail”,您可以使用 --pid=PID 参数并让 tail 处理它:
Specifically for 'tail' you could use the --pid=PID argument and let tail take care of it:
您可以按照 https://stackoverflow.com/a/38883662/565212 中的说明使用 get_pty。
例如场景 - 何时调用 client/channel.close():
第 1 步:执行写入日志文件的远程命令。
第2步:生成一个执行tail命令并阻塞在readline循环中的线程
第三步:在主线程中,当命令返回时,您知道不会有更多日志,杀死尾线程。
You can use get_pty as described in https://stackoverflow.com/a/38883662/565212.
E.g. scenario - When to call client/channel.close():
Step1: Execute a remote command that writes to the log file.
Step2: Spawn a thread that executes the tail command and blocks in the readline loop
Step3: In main thread, when the command returns, you know there will be no more logs, kill the tail thread.