web-dev-qa-db-fra.com

Exécuter des commandes interactives dans Paramiko

J'essaie d'exécuter une commande interactive via paramiko. L'exécution de cmd essaie de demander un mot de passe mais je ne sais pas comment fournir le mot de passe via exec_command de paramiko et l'exécution se bloque. Existe-t-il un moyen d'envoyer des valeurs au terminal si une exécution de cmd attend une entrée de manière interactive?

ssh = paramiko.SSHClient()
ssh.connect(server, username=username, password=password)
ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("psql -U factory -d factory -f /tmp/data.sql")

Est-ce que quelqu'un sait comment cela peut être abordé? Je vous remercie.

32
Sharmila

La distribution complète de paramiko est livrée avec beaucoup de bons démos .

Dans le sous-répertoire demos, demo.py et interactive.py ont des exemples interactifs complets de TTY qui seraient probablement excessifs dans votre cas.

Dans votre exemple ci-dessus, ssh_stdin se comporte comme un objet de fichier Python standard, donc ssh_stdin.write devrait fonctionner tant que le canal est toujours ouvert.

Je n'ai jamais eu besoin d'écrire sur stdin, mais la documentation suggère qu'un canal est fermé dès qu'une commande se ferme. Il est donc probable que l'utilisation de la méthode standard stdin.write pour envoyer un mot de passe ne fonctionnera pas. Il y a des commandes de paramiko de niveau inférieur sur le canal lui-même qui vous donnent plus de contrôle - voyez comment la méthode SSHClient.exec_command est implémentée pour tous les détails sanglants.

28
James Brady

J'ai eu le même problème en essayant de faire une session ssh interactive en utilisant ssh , un fork de Paramiko.

J'ai fouillé et trouvé cet article:

http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/

Pour continuer votre exemple, vous pourriez faire

ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("psql -U factory -d factory -f /tmp/data.sql")
ssh_stdin.write('password\n')
ssh_stdin.flush()
output = ssh_stdout.read()

L'article va plus en profondeur, décrivant un shell entièrement interactif autour de exec_command. J'ai trouvé cela beaucoup plus facile à utiliser que les exemples de la source.

7
afrosteve

Vous avez besoin de Pexpect pour tirer le meilleur parti des deux mondes (expect et ssh wrappers).

4
ax25
ssh = paramiko.SSHClient()
ssh.set_missing_Host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(server_IP,22,username, password)


stdin, stdout, stderr = ssh.exec_command('/Users/lteue/Downloads/uecontrol-CXC_173_6456-R32A01/uecontrol.sh -Host localhost ')
alldata = ""
while not stdout.channel.exit_status_ready():
   solo_line = ""        
   # Print stdout data when available
   if stdout.channel.recv_ready():
      # Retrieve the first 1024 bytes
      solo_line = stdout.channel.recv(1024) 
      alldata += solo_line
   if(cmp(solo_line,'uec> ') ==0 ):    #Change Conditionals to your code here  
     if num_of_input == 0 :
      data_buffer = ""    
      for cmd in commandList :
       #print cmd
       stdin.channel.send(cmd)        # send input commmand 1
      num_of_input += 1
     if num_of_input == 1 :
      stdin.channel.send('q \n')      # send input commmand 2 , in my code is exit the interactive session, the connect will close.
      num_of_input += 1 
print alldata
ssh.close()              

Pourquoi stdout.read () se bloquera-t-il si vous utilisez différemment sans vérifier stdout.channel.recv_ready (): in pendant que stdout.channel.exit_status_ready (): 

Dans mon cas, après la commande d’exécution sur le serveur distant, la session attend la saisie de l’utilisateur. Après la saisie de «q», la connexion sera fermée. Mais avant de saisir 'q', le stdout.read () attend EOF, semble que ce methord ne fonctionne pas si le tampon est plus grand.

  • J'ai essayé stdout.read (1) depuis, ça marche
    J'ai essayé stdout.readline () depuis, ça marche aussi.
    stdin, stdout, stderr = ssh.exec_command ('/ Users/lteue/Téléchargements/uecontrol')
    stdout.read () va se bloquer
3
kevin yu

Je ne suis pas familier avec paramiko, mais cela peut marcher: 

ssh_stdin.write('input value')
ssh_stdin.flush()

Pour plus d'informations sur stdin:

http://docs.python.org/library/sys.html?highlight=stdin#sys.stdin

3
monkut

Regardez l'exemple et faites de la même manière 

(extrait de http://jessenoller.com/2009/02/05/ssh-programming-with-paramiko-completely-different/ ):

    ssh.connect('127.0.0.1', username='jesse', 
        password='lol')
    stdin, stdout, stderr = ssh.exec_command(
        "Sudo dmesg")
    stdin.write('lol\n')
    stdin.flush()
    data = stdout.read.splitlines()
    for line in data:
        if line.split(':')[0] == 'AirPort':
            print line
0
Paweł Wojtal