2
votes

Problèmes lors de l'utilisation de Python vers des fichiers de transfert SCP sous Windows à l'aide d'os, Popen et Paramiko

J'essaie d'obtenir un script Python pour SCP transférer un fichier vers un serveur SSH auquel j'ai accès root et aucun mot de passe. Je suis sous Windows et j'exécute;

PS C:\scp_test> scp -v test.txt root@169.254.108.26:/data
Executing: program ssh.exe host 169.254.108.26, user root, command scp -v -t /data
OpenSSH_for_Windows_7.6p1, LibreSSL 2.6.4
debug1: Connecting to 169.254.108.26 [169.254.108.26] port 22.
debug1: Connection established.
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_rsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_rsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_dsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_dsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_ecdsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_ecdsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_ed25519 type -1
debug1: key_load_public: No such file or directory
debug1: identity file C:\\Users\\myself/.ssh/id_ed25519-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_for_Windows_7.6
debug1: Remote protocol version 2.0, remote software version dropbear_2017.75
debug1: no match: dropbear_2017.75
debug1: Authenticating to 169.254.108.26:22 as 'root'
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: algorithm: curve25519-sha256@libssh.org
debug1: kex: host key algorithm: ecdsa-sha2-nistp521
debug1: kex: server->client cipher: aes128-ctr MAC: hmac-sha2-256 compression: none
debug1: kex: client->server cipher: aes128-ctr MAC: hmac-sha2-256 compression: none
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ecdsa-sha2-nistp521 SHA256:RNaIuHs4U+5p8kQrcB+0pwCoKab3j6DNCk5hShNzpj4
debug1: Host '169.254.108.26' is known and matches the ECDSA host key.
debug1: Found key in C:\\Users\\myself/.ssh/known_hosts:4
debug1: rekey after 4294967296 blocks
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: rekey after 4294967296 blocks
debug1: pubkey_prepare: ssh_get_authentication_socket: No such file or directory
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentication succeeded (none).
Authenticated to 169.254.108.26 ([169.254.108.26]:22).
debug1: channel 0: new [client-session]
debug1: Entering interactive session.
debug1: pledge: network
debug1: Sending command: scp -v -t /data
Sending file modes: C0666 5430 test.txt
Sink: C0666 5430 test.txt
test.txt
100% 5430     5.3KB/s   00:00
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: channel 0: free: client-session, nchannels 1
Transferred: sent 7080, received 1376 bytes, in -7.0 seconds
debug1: Exit status 0

fonctionne comme un charme.

J'ai essayé plusieurs approches différentes pour que Python le fasse, mais je rencontre des problèmes peu importe quoi:

  1. Avec os :

    Traceback (most recent call last):
      File ".\my_script.py", line 6, in <module>
        ssh.connect('root@<ip-address>:data')
      File "C:\Users\myself\AppData\Local\Programs\Python\Python37-32\lib\site-packages\paramiko\client.py", line 334, in connect
        to_try = list(self._families_and_addresses(hostname, port))
      File "C:\Users\myself\AppData\Local\Programs\Python\Python37-32\lib\site-packages\paramiko\client.py", line 204, in _families_and_addresses
        hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM
      File "C:\Users\myself\AppData\Local\Programs\Python\Python37-32\lib\socket.py", line 748, in getaddrinfo
        for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
    socket.gaierror: [Errno 11003] getaddrinfo failed
    

    J'obtiens:

    Le chemin spécifié est introuvable (traduit donc le libellé peut être différent)

  2. Avec Popen :

    from paramiko import SSHClient
    from scp import SCPClient
    ssh = SSHClient()
    ssh.load_system_host_keys()
    ssh.connect('root@<ip-address>:data')
    with SCPClient(ssh.get_transport()) as scp:
        scp.put('test.txt', 'test.txt')`
    

    J'obtiens:

    FileNotFoundError: [WinError 2] Le fichier spécifié n'a pas été trouvé (encore une fois traduit)

    J'ai essayé de pointer vers OpenSSH \ scp.exe de plusieurs manières, mais en vain.

  3. Avec Paramiko:

    import subprocess
    p = subprocess.Popen(['scp', 'test.txt', 'root@<ip-address>:/data'])
    sts = os.waitpid(p.pid, 0)`
    

    J'obtiens:

    import os
    my_scp = r'C:\Windows\System32\OpenSSH\scp.exe'
    os.system(my_scp + ' test.txt root@<ip-address>:/data')
    

J'utilise Python 3.7.3 sous Windows 10.


Mise à jour - exécute scp -v :

scp test.txt root@<ip-address>:/data

Mise à jour II: je l'ai fait fonctionner en réinstallant Python en 64 bits et en utilisant os pour appeler OpenSSH.


4 commentaires

Le deuxième cas aurait dû fonctionner si le fichier avait existé. Vous l'avez probablement exécuté à partir d'un répertoire différent de celui qui contient le fichier que vous souhaitez copier, ou vous avez mal orthographié son nom.


Le problème était d'appeler OpenSSH 64 bits exécutant Python 32 bits, comme indiqué par Martin Prikryl ci-dessous. Après la réinstallation de Python 64 bits, les deux cas 1 et 2 fonctionnent.


Vous avez utilisé C: \ Windows \ sysnative \ OpenSSH \ sftp - et vous n’avez pas besoin de réinstaller Python.


J'ai essayé cette option mais cela a généré une erreur. Je ne me souviens pas exactement de quoi - il a exécuté OpenSSH, mais n'a pas transféré le fichier.


3 Réponses :


0
votes

Vous utilisez Paramiko SSHClient.connect incorrectement.

Le premier argument de SSHClient.connect est hostname (ce qui peut être aussi une adresse IP comme dans votre cas ). Aucun nom d'utilisateur ou quoi que ce soit d'autre ne peut y être. Le nom d'utilisateur va à l'argument username . Le chemin de destination (qui n'a rien à voir avec la connexion SSH) va uniquement à SCPClient.put.

Cela devrait fonctionner:

ssh = SSHClient()
ssh.load_system_host_keys()
ssh.connect('<ip-address>', username='root')
with SCPClient(ssh.get_transport()) as scp:
    scp.put('test.txt', '/data/test.txt')

Concernant vos tentatives d'utilisation de scp : Juste une supposition sauvage, mais je suppose que vous utilisez la version Win32-OpenSSH d'OpenSSH. Il n'est disponible qu'en version 64 bits. Si vous utilisez Python 32 bits, il ne peut pas trouver les outils OpenSSH 64 bits, comme scp , car ils sont dans la version 64 bits de C: \ Windows \ System32 . Vous pouvez y accéder via le nom magique C: \ Windows \ sysnative \ OpenSSH \ sftp . En savoir plus sur File System Redirector . Cependant, vous ne devez pas exécuter une application console pour implémenter SCP. Utilisez l'implémentation native de Python SCP, comme SCPClient.


7 commentaires

Salut Martin, Merci d'avoir signalé l'erreur lors de l'utilisation de Paramiko. Cela ne fonctionne cependant pas après ce correctif. J'obtiens exactement le même message d'erreur. Vous avez raison sur les versions binaires - Python 32 bits et OpenSSH 64 bits. Avez-vous d'autres idées sur Paramiko ou réinstaller Python en 64 bits et utiliser OpenSSH est l'option la plus simple?


Ma réponse montre clairement que vous devez faire ssh.connect ('', username = 'root') , pas ssh.connect ('root @ ', username =' root ') - Le premier argument de connect est hostname (ce qui peut être aussi une adresse IP comme dans votre cas). Aucun nom d'utilisateur ou quoi que ce soit d'autre ne peut y être. Lisez la documentation. C'est lié dans ma réponse.


Vous avez absolument raison - j'avais «root @ IP» comme suggéré dans l'exemple que je suivais - D'oh! :-( Après avoir effacé cela, maintenant j'obtiens: lever SSHException ("Aucune méthode d'authentification disponible"). Comme je n'ai pas de mot de passe pour l'appareil auquel j'essaie de me connecter, je suppose que je dois établir des clés SSH sur les deux appareils ..?


Vous avez écrit que scp fonctionne. Il doit s'authentifier en quelque sorte . Tu ne sais pas comment? Il utilise très probablement une clé privée (vous saurez s'il a utilisé un mot de passe). Utilisez donc la même clé dans Paramiko.


Je ne sais pas comment il s'authentifie. Je n'ai pas configuré le serveur moi-même - c'est pour autant que je sache un Raspberry pi intégré dans l'appareil, auquel je me connecte via USB. Je sais avec certitude que je n'ai configuré aucune clé sur mon ordinateur client.


Montrez-nous une sortie de scp -v test.txt root @ : / data


OK, donc votre serveur SSH ne nécessite en effet aucune authentification. Implémenter cela dans Paramiko est une question intéressante, mais qui dépasse la portée de votre message d'origine. Pensez à poser une nouvelle question pour cela.



-1
votes

Un problème possible avec votre première approche est que vous devez doubler vos barres obliques inverses. Les barres obliques inverses sont utilisées dans les chaînes pour désigner des caractères spéciaux, mais si vous voulez juste une barre oblique inverse, vous voulez en avoir deux

import os
my_scp = r'C:\\Windows\\System32\\OpenSSH\\scp.exe'
os.system(my_scp + ' test.txt root@<ip-address>:/data')


2 commentaires

Vous n'avez pas besoin d'échapper aux contre-obliques dans les chaînes brutes.


Ah oui tu as raison. C'est mon mal de ne pas voir ça



0
votes

solution trouvée si Win10 64 bits et Python 32 bits (3.8):

a = 'scp -r -i "path_to_your_key" path_to_file_want_to_send login@server_or_ip:path_on_server'
#  Also work if add ssh line to the a
# a += "\nssh -i path_to_your_key login@server_or_ip \"SOME COMMAND TO DO ON SERVER\""

filename = "sendjob.bat"
s = open(filename, "w+")
s.write(a)
s.close()
os.system('c:\windows\syswow64\cmd.exe /c c:\windows\sysnative\cmd.exe /c start ' + filename)

Ma configuration: Ordinateur portable de bureau Win10 sans autorisation root et j'avais besoin d'envoyer des fichiers au serveur Linux et d'y faire quelque chose.


0 commentaires