Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 16/07/2010, à 12:37

bejazzy

[Python] Interrompre stdin/stdout bloquant

Bonjour à tous,

Contexte
Je développe quelques outils Python dans le but à la fois (1) de récupérer des informations sur des machines distantes: uptime, free, nombre de coeurs, ...) et (2) de lancer des programmes sur ces mêmes machines. Et le tout via SSH. Les programmes pouvant être lancés sont de tout type, il suffit de spécifier le chemin du programme avec ces arguments. Cela peut-être un script Python, un exécutable C++ ou un script Bash, peu importe.

Pour récupérer quelques infos sur un hôte distant:

$ ssh hostname uptime
12:18:18 up 1 day, 23:23,  3 users,  load average: 0.01, 0.18, 0.19

Je traite ensuite le retour de cette commande pour ne prendre que la charge CPU moyenne sur 1 minute.
Pour lancer des programmes, même chose:

$ ssh hostname /path/to/my_program

Pour faire ces opérations, j'utilise le module subprocess et la classe Popen. Je peux lancer tout plein de requêtes et de programmes tout en gardant la main. J'entends par là que je n'attends pas le retour ou la fin de mon programme pour en lancer un autre. Un example:

import subprocess

hostname_list = ['arakis', 'gesserit', 'atreides']
subprocess_list = []
for host in hostname_list:
    command_name = "ssh %s uptime" % host
    subprocess_list.append(subprocess.Popen([command_name], shell = True,
                                            stdout = subprocess.PIPE,
                                            stderr = subprocess.PIPE))

Je peux ensuite récupérer la sortie standard et erreur standard de mes programmes avec la méthode communicate() pour chacun des processus.

Problème:

Selon la configuration SSH sur le groupe de machines, il peut y avoir des messages bloquants. Je ne pense pas que ces messages soient considérés comme des messages d'erreur. Il peut y en avoir de plusieurs type.
  1. Avoir oublié de faire ssh-add pour éviter de taper à chaque fois la passphrase.

Enter passphrase for RSA key 'login@hostname':

ou

Enter passphrase for key '/home/login/.ssh/id_rsa':

2. Demande de mot de passe de la machine distance.

login@hostname's password:

3. Ajouter le nom de la machine distance au fichier .ssh/known_host.

The authenticity of host 'hostname (aaa.bb.cc.ddd)' can't be established.
    RSA1 key fingerprint is ef:51:8x:bm:d7:8z:7f:7d:f0:9d:15:aa:11:cd:f5:94.
    Are you sure you want to continue connecting (yes/no)?

J'ai résolu le 3e point forçant ma propre configuration SSH en ajoutant l'option StrictHostKeyChecking no.

Pour ces 3 cas, le script Python qui me permet de lancer toutes ces commandes s'interrompt, un message (la sortie standard) me demande de taper quelque chose au clavier (entrée standard). Et la seule solution que j'ai, c'est de faire un brutal Ctrl-C ou Ctrl-Z pour sortir de ce bazar, résoudre le problème lié au message puis recommencer.

Je souhaite savoir s'il y a un moyen "d'écouter", de "regarder" si l'entrée standard est en attente d'une saisie clavier pour afficher un quelconque message et arrêter le script. Il peut y avoir par exemple un problème sur une machine distance et une seule, et le message bloquant empêche de continuer à lancer des programmes sur d'autres machines.

Jusqu'à maintenant:
 
J'ai regardé les modules select, termios, tty de Python sans trop comprendre (même avec quelques exemples). En particulier, j'ai testé 2 scripts pour comprendre comment tout cela fonctinne:
  * http://www.developpez.net/forums/d607146/autres-langages/python-zope/general-python/test-non-bloquant-presence-caracteres-sys-stdin/
  * http://www.darkcoding.net/software/non-blocking-console-io-is-not-possible/
 
Le premier lien est une implémentation d'un thread qui lit la sortie standard et qui permet d'envoyer un SystemExit quand on appuie sur les touches Ctrl-C. Le 2e est assez similaire et donne un exemple de lecture clavier tout en faisant une boucle. Cette boucle s'arrête si on appuie sur Esc. Néanmoins, cela ne me permet pas de faire ce que je souhaite.

Objectif:
 
Lancer un thread qui vérifie si le système demande une saisie clavier et affiche un message et quitte si c'est le cas. Je souhaite lancer ce thread un faire un test avec un simple:

out = raw_input("Quelque chose: ")

et voir si mon thread comprend que le système demande une saisie clavier.

J'espère ne pas avoir été trop long et trop évasif. Je ne suis pas un craque en programmation système. Si quelqu'un a même des explications/tutoriels/manpages ou autres sur la manipulation de tels concepts (tty, termios, etc) en autres choses que Python (SHELL, C), je suis preneur.

Merci à tous.


Dell Inspiron 1525 - #!CrunchBang Linux 10 Statler Xfce --- #! FR

Hors ligne

#2 Le 16/07/2010, à 12:50

ADcomp

Re : [Python] Interrompre stdin/stdout bloquant

Salut ,

Pour +/- les mêmes raisons* , j'ai utilisé le module pexpect ..

* projet pysshfs : pysshfs_0.2.tar.bz2


David [aka] ADcomp

Hors ligne

#3 Le 16/07/2010, à 13:45

bejazzy

Re : [Python] Interrompre stdin/stdout bloquant

Merci ADcomp !

Je regarde tout ça. À la fois ton script pysshfs et le module pexpect. J'espère trouvé une solution...


Dell Inspiron 1525 - #!CrunchBang Linux 10 Statler Xfce --- #! FR

Hors ligne