Длительные команды ssh в модуле python paramiko (и как их завершить) - PullRequest
22 голосов
/ 17 апреля 2009

Я хочу запустить команду tail -f logfile на удаленной машине с помощью модуля paramiko в python. До сих пор я пытался сделать это следующим образом:

interface = paramiko.SSHClient()
#snip the connection setup portion
stdin, stdout, stderr = interface.exec_command("tail -f logfile")
#snip into threaded loop
print stdout.readline()

Я бы хотел, чтобы команда выполнялась столько времени, сколько необходимо, но у меня есть 2 проблемы:

  1. Как мне остановить это чисто? Я подумал о создании канала, а затем использовал команду shutdown() на канале, когда закончил с ним, но это кажется грязным. Можно ли сделать что-то вроде отправки Ctrl-C на стандартный канал?
  2. readline() блоков, и я мог бы избежать потоков, если бы у меня был неблокирующий метод получения вывода - есть мысли?

Ответы [ 5 ]

21 голосов
/ 20 апреля 2009

Вместо вызова exec_command на клиенте, заполучите транспорт и создайте свой собственный канал. канал может использоваться для выполнения команды, и вы можете использовать ее в операторе выбора, чтобы выяснить, когда можно прочитать данные:

#!/usr/bin/env python
import paramiko
import select
client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect('host.example.com')
transport = client.get_transport()
channel = transport.open_session()
channel.exec_command("tail -f /var/log/everything/current")
while True:
  rl, wl, xl = select.select([channel],[],[],0.0)
  if len(rl) > 0:
      # Must be stdout
      print channel.recv(1024)

Объект канала может считываться и записываться, соединяясь с stdout и stdin удаленной команды. Вы можете получить на stderr, позвонив channel.makefile_stderr(...).

Я установил время ожидания на 0.0 секунд, потому что было запрошено неблокирующее решение. В зависимости от ваших потребностей, вы можете заблокировать с ненулевым таймаутом.

14 голосов
/ 07 мая 2009

1) Вы можете просто закрыть клиента, если хотите. Сервер на другом конце уничтожит хвостовой процесс.

2) Если вам нужно сделать это неблокирующим образом, вам придется использовать объект канала напрямую. Затем вы можете отслеживать stdout и stderr с помощью channel.recv_ready () и channel.recv_stderr_ready () или использовать select.select.

8 голосов
/ 15 февраля 2013

Небольшое обновление от Эндрю Айлетта. Следующий код фактически разрывает цикл и завершает работу после завершения внешнего процесса:

import paramiko
import select

client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect('host.example.com')
channel = client.get_transport().open_session()
channel.exec_command("tail -f /var/log/everything/current")
while True:
    if channel.exit_status_ready():
        break
    rl, wl, xl = select.select([channel], [], [], 0.0)
    if len(rl) > 0:
        print channel.recv(1024)
0 голосов
/ 25 июня 2012

Только для информации, есть решение сделать это с помощью channel.get_pty (). Для более подробной информации смотрите: https://stackoverflow.com/a/11190727/1480181

0 голосов
/ 18 апреля 2009

Чтобы закрыть процесс, просто запустите:

interface.close()

С точки зрения неблокирования, вы не можете получить неблокирующее чтение. Лучшее, что вы могли бы сделать, - это анализировать по одному «блоку» за раз, «stdout.read (1)» будет блокироваться, только если в буфере не осталось символов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...