example - subprocess python español
Cómo llamar a ssh por módulo de subproceso para que use la variable SSH_ASKPASS (3)
Estoy escribiendo una GUI que usa comandos SSH. Traté de usar el módulo de subproceso para llamar a ssh y establecer la variable de entorno SSH_ASKPASS para que mi aplicación pueda mostrar una ventana que solicita la contraseña de SSH. Sin embargo, no puedo hacer que ssh lea la contraseña usando el comando SSH_ASKPASS dado: siempre lo solicita en la ventana del terminal, independientemente de cómo configuro las variables de entorno DISPLAY, SSH_ASKPASS, TERM o cómo canalizo la entrada / salida estándar. ¿Cómo puedo asegurarme de que ssh está separado del TTY actual y usar el programa dado para leer la contraseña?
Mi código de prueba fue:
#!/usr/bin/env python
import os
import subprocess
env = dict(os.environ)
env[''DISPLAY''] = '':9999'' # Fake value (trying in OS X and Windows)
del env[''TERM'']
env[''SSH_ASKPASS''] = ''/opt/local/libexec/git-core/git-gui--askpass''
p = subprocess.Popen([''ssh'', ''-T'', ''-v'', ''[email protected]''],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env
)
p.communicate()
SSH usa la variable SSH_ASKPASS solo si el proceso está realmente separado de TTY (la redirección stdin y la configuración de variables de entorno no son suficientes). Para separar un proceso de la consola, debe bifurcar y llamar a os.setsid (). Entonces, la primera solución que encontré fue:
# Detach process
pid = os.fork()
if pid == 0:
# Ensure that process is detached from TTY
os.setsid()
# call ssh from here
else:
print "Waiting for ssh (pid %d)" % pid
os.waitpid(pid, 0)
print "Done"
También hay una manera elegante de hacerlo utilizando el módulo de subproceso: en el argumento preexec_fn podemos pasar una función de Python que se llama en el subproceso antes de ejecutar el comando externo. Entonces, la solución para la pregunta es una línea adicional:
env = {''SSH_ASKPASS'':''/path/to/myprog'', ''DISPLAY'':'':9999''}
p = subprocess.Popen([''ssh'', ''-T'', ''-v'', ''[email protected]''],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env,
preexec_fn=os.setsid
)
Su problema es que SSH detecta su TTY y habla con él directamente (como se establece claramente en la página de manual). Puede probar y ejecutar ssh sin un terminal: la página man sugiere que podría ser necesario redirigir stdin
a /dev/null
para que ssh piense que no tiene terminal.
También puede usar pexcept para esto, se sabe que funciona con SSH - uso de ejemplos.
The Right Way (TM) para hacer lo que estás tratando de hacer es:
- Utilice una biblioteca específicamente para usar SSH en python (por ejemplo, conch twisted o paramiko )
- Use claves públicas y privadas para que las contraseñas no sean necesarias
Si desea una forma rápida y sucia de hacerlo para su uso personal, puede habilitar el inicio de sesión sin contraseña entre estas dos máquinas haciendo esto en su terminal:
ssh-keygen -t rsa # generate a keypair (if you haven''t done this already)
ssh-copy-id user@other_machine # copy your public key to the other machine
Luego puede obtener los comandos ssh (el subproceso no parece aceptar los comandos ssh directamente) al crear un script (recuerde marcarlo como ejecutable, por ejemplo, chmod 755 my_script.sh
) con las cosas que desee, como por ejemplo:
#!/bin/bash
ssh user@other_machine ls
y llámalo desde tu programa:
import subprocess
response = subprocess.call("./my_script.sh")
print(response)
Para la producción, el uso de aplicaciones que deben implementarse en las máquinas de otras personas, me gustaría ir con el enfoque de Abyx de usar una biblioteca SSH. Mucho más simple que jugar con algunas variables de entorno.