De longa execução comandos ssh no módulo python paramiko (e como acabar com eles)

StackOverflow https://stackoverflow.com/questions/760978

  •  09-09-2019
  •  | 
  •  

Pergunta

Eu quero executar um comando tail -f logfile em uma máquina remota usando o módulo paramiko de python. Eu tenho tentado até agora da seguinte forma:

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

Eu gostaria de comando para executar, desde que necessário, mas eu tenho 2 problemas:

  1. Como posso parar com isso de forma limpa? Pensei em fazer um canal e, em seguida, usando o comando shutdown() no canal quando eu terminar com ele- mas que parece confuso. É possível fazer algo como Ctrl-C enviado para stdin do canal?
  2. blocos readline(), e eu podia evitar tópicos se eu tivesse um método não-bloqueio de obter output- todos os pensamentos?
Foi útil?

Solução

1) Você pode apenas perto o cliente, se desejar. O servidor do outro lado vai matar o processo de cauda.

2) Se você precisa fazer isso de uma maneira non-blocking, você terá que usar o objeto canal diretamente. Você pode então assistir para ambos stdout e stderr com channel.recv_ready () e channel.recv_stderr_ready (), ou o uso select.select.

Outras dicas

Em vez de chamar exec_command no cliente, se apossar do transporte e gerar o seu próprio canal. A canalizar pode ser usado para executar um comando, e você pode usá-lo em uma instrução SELECT para descobrir quando os dados podem ser lidos:

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

O objeto canal podem ser lidos e gravados, conectando com stdout e stdin do comando remoto. Você pode obter no stderr chamando channel.makefile_stderr(...).

Eu definir o tempo limite para segundos 0.0 porque uma solução não-bloqueio foi solicitado. Dependendo de suas necessidades, você pode querer bloquear com um tempo limite diferente de zero.

Apenas uma pequena atualização para a solução por Andrew Aylett. O código a seguir realmente quebra o circuito e sai quando o processo externo acabamentos:

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)

Para fechar o processo de simplesmente executar:

interface.close()

Em termos de não bloqueante, você não pode obter uma leitura não bloqueante. O melhor que você seria capaz da seria para analisar sobre ele um "bloco" de cada vez, "stdout.read (1)" só vai bloquear quando não há caracteres restantes no buffer.

Apenas para informação, não é uma solução para fazer isso usando channel.get_pty (). mais Fore detalhes têm uma olhada em: https://stackoverflow.com/a/11190727/1480181

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top