Подтвердить что ты не робот

Paramiko и exec_command - убивающий удаленный процесс?

Я использую Paramiko для tail -f файла на удаленном сервере.

Раньше мы запускали это через ssh -t, но это оказалось flaky, а -t вызвало проблемы с нашей системой удаленного планирования.

Мой вопрос: как убить хвост, когда script ловит SIGINT?

My script (на основе Долгосрочные команды ssh в модуле python paramiko (и как их закончить))

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

script успешно завершает мой Ctrl-C и заканчивается. Однако он оставляет процесс tail -f запущенным в удаленной системе,

Ни client.close(), ни channel.close(), похоже, не завершают его.

Какую команду я могу задать в блоке except, чтобы ее убить?

На удаленном сервере работает Solaris 10.

4b9b3361

Ответ 1

Хотя это не самый эффективный метод, это должно сработать. После вас 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 open, что вы не хотите закрывать, если это возможно, grep a ps, получите pid и kill -9 его.

Сначала установите хвост для чтения строк 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))

Ответ 2

Есть один способ сделать это. Он работает как на оболочке

ssh -t commandname

Опция -t открывает псевдо-pty, чтобы помочь ssh отслеживать, как долго этот процесс должен продолжаться. то же самое можно сделать через pormiko через

channel.get_pty()

до команды execute_command (...). Это не откроет оболочку, как это происходит с channel.invoke_shell(), она просто запрашивает такой псевдо-интерфейс для привязки всех процессов. Эффект можно также увидеть, если ps aux выдается на удаленном компьютере, теперь процесс привязан к sshd с интерфейсом ptxXY.

Ответ 3

Вы должны использовать ssh keepalives... проблема заключается в том, что удаленная оболочка не знает (по умолчанию), что ваш сеанс ssh был убит. Keepalives позволит удаленной оболочке обнаружить, что вы убили сеанс

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 секунду)... через несколько секунд удаленная оболочка увидит, что имя пользователя ssh умерло, и оно прекратит любые процессы, которые были созданы им.

Ответ 4

Я просто ударил эту проблему и не смог выпустить pkill, чтобы закрыть процесс в конце.

Лучшее решение - изменить команду, в которой вы работаете:

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

Это позволит вам запускать команду хвоста столько, сколько вам нужно. Как только вы отправите новую строку в удаленный процесс, kill% 1 выполнит и остановит команду хвоста, которую вы создали. (для справки:% 1 является спецификацией jobs и используется для описания первого процесса, который был задан в вашей сессии, то есть команды хвоста)

Ответ 5

Здесь можно получить идентификатор удаленного процесса:

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

Ответ 6

В частности, для "хвоста" вы можете использовать аргумент -pid = PID и позволить хвосту позаботиться об этом:

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

Ответ 7

Вы можете использовать get_pty, как описано в fooobar.com/questions/241659/....

например. сценарий - когда вызывать client/channel.close():
Шаг1: Выполните удаленную команду, которая записывает в файл журнала.
Шаг 2: Создайте поток, который выполняет команду хвоста и блокирует цикл цикла чтения
Шаг 3: В основном потоке, когда команда вернется, вы знаете, что больше не будет журналов, убейте хвост.

Ответ 8

Была та же проблема с ssh -t. Существует библиотека под названием closer - она ​​запускает удаленный процесс через ssh и автоматически закрывается для вас. Проверьте это.