Paramiko and exec_command - killing remote process?

前端 未结 8 1606
情书的邮戳
情书的邮戳 2020-12-09 05:09

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

相关标签:
8条回答
  • 2020-12-09 05:17

    There is one way to do this. It works like on the shell

    ssh -t commandname
    

    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

    channel.get_pty()
    

    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.

    0 讨论(0)
  • 2020-12-09 05:24

    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

    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...
    

    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.

    0 讨论(0)
  • 2020-12-09 05:29

    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:

    #!/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)
    

    This would kill any open processes named tail. That may cause issues though if you have tails open that you dont want to close, if thats the case you could grep a ps, get the pid and kill -9 it.

    First, set tail to read n lines from end of file before following. set n to a unique nuber like time.time(), since tail doesn't care if that number is larger then the number of lines in the file, the large number from time.time()shouldnt cause issues and will be unique. Then grep for that unique number in the 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))
    
    0 讨论(0)
  • 2020-12-09 05:31

    Here's a way to obtain the remote process 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
    

    And here's how to use it (replace ... with the bits in the original question):

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

    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.

    0 讨论(0)
  • 2020-12-09 05:34

    Specifically for 'tail' you could use the --pid=PID argument and let tail take care of it:

      --pid=PID  with -f, terminate after process ID, PID dies
    
    0 讨论(0)
提交回复
热议问题