首页 文章

Paramiko和exec_command - 杀死远程进程?

提问于
浏览
13

我正在将Paramiko用于 tail -f 远程服务器上的文件 .

以前,我们通过 ssh -t 运行此功能,但事实证明这种情况不稳定, -t 导致我们的远程调度系统出现问题 .

我的问题是当脚本捕获SIGINT时如何杀死尾巴?

我的脚本(基于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)

该脚本成功捕获我的Ctrl-C,然后结束 . 但是,它使 tail -f 进程在远程系统上运行 .

client.close()和channel.close()似乎都没有终止它 .

我可以在except块中发出什么命令来杀死它?

远程服务器正在运行Solaris 10 .

8 回答

  • 0

    虽然不是最有效的方法,但这应该有效 . CTRL C之后;在KeyboardInterrupt处理程序中,你可以 exec_command("killall -u %s tail" % uname) 像这样:

    #!/usr/bin/env python2
    
    import paramiko
    import select
    
    import time
    ltime = time.time()
    
    # Or use random:
    # import random
    # ltime = random.randint(0, 500)
    
    uname = "victorhooi"
    client = paramiko.SSHClient()
    client.load_system_host_keys()
    client.connect('someserver', username=uname, password='blahblah')
    transport = client.get_transport()
    channel = transport.open_session()
    
    channel.exec_command("tail -%df /home/victorhooi/macbeth.txt" % ltime)
    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")
            channel.close()
            try:
                # open new socket and kill the proc..
                client.get_transport().open_session().exec_command("kill -9 `ps -fu %s | grep 'tail -%df /home/victorhooi/macbeth.txt' | grep -v grep | awk '{print $2}'`" % (uname, ltime))
            except:
                pass
        
            client.close()
            exit(0)
    

    这会杀死任何名为 tail 的打开进程 . 这可能会导致问题,但如果你打开了 tail ,你不想关闭,如果是这样你可以 grep a ps ,得到pid和 kill -9 它 .

    首先,设置tail以从文件末尾读取 n 行,然后再执行 . 将 n 设置为一个独特的nuber,如 time.time() ,因为尾部不关心该数字是否大于文件中的行数, time.time() 中的大数字不应该导致问题并且将是唯一的 . 然后grep为 ps 中的唯一编号:

    client.get_transport().open_session().exec_command("kill -9 `ps -fu %s | grep 'tail -%df /home/victorhooi/macbeth.txt' | grep -v grep | awk '{print $2}'`" % (uname, ltime))
    
  • 1

    有一种方法可以做到这一点 . 它就像在shell上一样

    ssh -t commandname
    

    选项-t是打开一个伪pty来帮助ssh跟踪这个过程应该持续多长时间 . 同样可以通过pormiko via完成

    channel.get_pty()
    

    在execute_command(...)之前 . 这不会像使用channel.invoke_shell()一样打开shell,它只是请求这样的伪接口将所有进程绑定到 . 如果在远程计算机上发出ps aux,也可以看到效果,此过程现在通过ptxXY接口附加到sshd .

  • 6

    你应该使用ssh keepalive ...你遇到的问题是远程shell无法知道(默认情况下)你的ssh会话被杀死了 . Keepalive将使远程shell能够检测到您已杀死会话

    client = paramiko.SSHClient()
    client.load_system_host_keys()
    client.connect('someserver', username='victorhooi', password='blahblah')
    transport = client.get_transport()
    transport.set_keepalive(1)   # <------------------------------
    # ... carry on as usual...
    

    将keepalive值设置为您想要的最低值(甚至1秒)......几秒钟后,远程shell将看到ssh登录名死亡,它将终止由它生成的任何进程 .

  • 0

    我刚刚遇到这个问题,并且无法在最后发出关闭该过程的pkill .

    更好的解决方案是将您正在运行的命令更改为:

    tail -f /path/to/file & { read ; kill %1; }
    

    这将允许您根据需要运行tail命令 . 只要您向远程进程发送换行符,kill%1就会执行并停止后退命令 . (供参考:%1是一个jobspec,用于描述在会话中已经背景化的第一个进程,即tail命令)

  • 4

    这是获取远程进程ID的一种方法:

    def execute(channel, command):
        command = 'echo $$; exec ' + command
        stdin, stdout, stderr = channel.exec_command(command)
        pid = int(stdout.readline())
        return pid, stdin, stdout, stderr
    

    以下是如何使用它(用原始问题中的位替换 ... ):

    pid, _, _, _ = execute(channel, "tail -f /home/victorhooi/macbeth.txt")
    while True:
        try:
            # ...
        except KeyboardInterrupt:
            client.exec_command("kill %d" % pid)
            # ...
    
  • 0

    特别是对于'tail',你可以使用--pid = PID参数并让tail来处理它:

    --pid=PID  with -f, terminate after process ID, PID dies
    
  • 5

    您可以使用https://stackoverflow.com/a/38883662/565212中所述的get_pty .

    例如 . scenario - 何时调用client / channel.close():
    步骤1:执行写入日志文件的远程命令 .
    Step2:生成一个执行tail命令的线程,并在readline循环中阻塞
    Step3:在主线程中,当命令返回时,你知道将不再有日志,杀死尾线程 .

  • 0

    ssh -t 有同样的问题 . 有一个名为closer的库 - 它通过ssh运行远程进程并自动关闭 . 看看这个 .

相关问题