Pythonでサーバーにリモート登録する手順


Pythonを使ってシナリオを書く場合、ある場合、リモートサービスに頻繁にログインしてコマンドを実行し、結果を返します。
shell環境の中で、私達はこのようにしました。

$ sshpass -p ${passwd} ssh -p ${port} -l ${user} -o StrictHostKeyChecking=no xx.xx.xx.xx "ls -l"
そして、あなたの出力は多くあります。必要ではないですが、落ちられない情報があります。このようにしてください。

host: xx.xx.xx.xx, port: xx
Warning: Permanently added '[xx.xx.xx.xx]:xx' (RSA) to the list of known hosts.
Login failure: [Errno 1] This server is not registered to rmp platform, please confirm whether cdn server.
total 4
-rw-r--r-- 1 root root 239 Mar 30  2018 admin-openrc
shellコマンドを直接使用してコマンドを実行する場合は、配管を直接使用したり、標準出力をファイルにリダイレクトする方法で実行コマンドの返却結果を取得したりすることができます。
1.subprocessを使う
Pythonを使ってこのことをすれば、普通は第一時間で、os.popen、os.system、command、subprocessなどの命令実行ライブラリを使って間接的に取得したいです。
しかし、私が知っている限りでは、これらのライブラリは標準出力だけでなく、標準エラー(つまり上記の余分な情報)も含んでいます。
ですから、outputのデータは毎回洗浄して、フォーマットを整えてから、私たちが欲しいデータが得られます。
subprocessで例を挙げると、このようになります。

import subprocess
ssh_cmd = "sshpass -p ${passwd} ssh -p 22 -l root -o StrictHostKeyChecking=no xx.xx.xx.xx  'ls -l'"
status, output = subprocess.getstatusoutput(ssh_cmd)

#     ,         
<code...>
以上の文字+コードの展示を通して、ssh登録の大きな痛みを感じられます。
  • 痛点一:追加でsshpassをインストールする必要があります。
  • 痛み点2:干渉情報が多すぎて、データの整理、フォーマットがかなり面倒です。
  • 痛点三:コードの実現が足りない(土っぽい)、可読性が悪い
  • 痛点四:ssh接続は多重化できません。一回の接続は一回だけ実行できます。
  • 痛み点5:コードは全プラットフォームができなくて、LinuxとOSXだけで
  • を使うことができます。
    これらの問題を解決するために、Python sshに関するネット全体の文章を検索しましたが、この方面の技術を完全に紹介しているのは見られませんでした。
    このために、私はとても人気のあるGithubプロジェクトを見ました。awesome-python-cn(https://github.com/BingmingWong/awesome-python-cn)。
    ここで、遠隔接続に関するいくつかの有用なライブラリを見つけることを期待しています。
    本当に二つ見つけられました。
  • sh.ssh
  • パミコ
  • 2.sh.sshを使う
    まず最初に紹介します。sh.ssh。
    shは関数の呼び出しでLinxu/OSXシステムコマンドを完成させるライブラリです。とても使いやすくて、それについても紹介します。
    
    $ python3 -m pip install sh
    今日はその中の一つの関数を紹介します。
    通常は2台のマシンが相互訪問していますが、便利のために、無料でログインできるようにしています。パスワードを入力する必要はありません。
    このコードは非密登録を実現し、私達の命令ls-lを実行します。
    
    from sh import ssh
    output=ssh("[email protected]", "-p 22", "ls -l")
    print(output)
    しかし、可能性があります。私たちはお互いに信頼できる秘密を設定したくないです。このコードをもっと通用させるために、私たちは秘密保護を設けていないと仮定して、パスワードを使って登録するしかないです。
    問題が来ました。パスワードを入力するには、対話式の方法で入力しなければなりません。Pythonではどうやって実現しますか?
    もとはssh方法で_を受信しました。outパラメータは、このパラメータは文字列としてもよく、ファイルパスを示しても良いし、ファイルオブジェクト(またはクラスファイルオブジェクト)としても良いし、標準出力がある場合には出力内容をこの関数に伝えるように呼び出すという意味です。
    これでいいですね。
    私はpassword:という文字があると認識したら、私のパスワードを標準に入力してください。
    完全コードは以下の通りです。
    
    import sys
    from sh import ssh
    
    aggregated = ""
    def ssh_interact(char, stdin):
        global aggregated
        sys.stdout.write(char.encode())
        sys.stdout.flush()
        aggregated += char
        if aggregated.endswith("password: "):
            stdin.put("you_password
    ") output=ssh("[email protected]", "-p 22", "ls -l",_tty_in=True, _out_bufsize=0, _out=ssh_interact) print(output)
    これは公式文書(http://amoffat.github.io/sh/tutorials/interacting_with_processes.highlight=ssh)からの情報に基づいて、デモを書いたものです。
    テストを実行してみたら、プログラムはずっと実行中です。いつまでも戻ってこないし、終了しないし、コールバック関数も永遠に入れないです。
    デバッグでソースコードを調べても問題点が見つからないので、Githubで調べてみましたが、2017年にはすでにこの問題が存在していました。2020年になってもまだ修復されていません。sh.sshを使う人は多くないようです。そこで私はまた“問い詰め”して、回答を期待しています。

    以上の問題は、パスワードを入力しないと発生しません。機械の相互信頼を設定すれば大丈夫です。
    sh.sshの使用効果を実感するために、機械相互信頼を設定し、以下のコードを使用します。
    
    from sh import ssh
    
    my_server=ssh.bake("[email protected]", "-p 22")
    
    #                ,        
    print(my_server.ls())
    
    #    sleep   ,       ,   top ,            
    time.sleep(5)
    
    #          ,       +1,    ,   -1
    print(my_server.ifconfig())
    bakeという方式を使っていることに驚きました。my_server.ls()とmy_server.ifconfig()このように同じssh接続で2回のコマンドを実行しているように見えますが、実際には、リモートマシンでtopコマンドを実行して接続された端末の変化を見ることができます。まず+1から-1まで、2回のコマンドの実行は2回の接続によって実現されると説明します。
    このように見て、sh.sshを使って痛みの点の1(もし上述の問題が解決することができるならば)、痛みの2、痛みの3を解決することができます。
    しかし、まだssh接続を多重化することができません。やはり不便です。私の理想の中で一番いい方法ではありません。
    一番重要な点は、shというモジュールはサポートのみです。 Lixu/OSXは、Windowsでは兄弟ライブラリ-pbsを使用して、また行きます。 pypeiはpbsを一目見ましたが、もう「長い間修理をしませんでした。」

    ここで私は「卒」を離れて、あと一本の藁を使うところでした。
    3.パラミコを使う
    最後の希望を持って、パラミコという倉庫を使ってみましたが、ようやくパラミコのところに来て、Pythonの優雅さを取り戻しました。
    次の命令でインストールできます。
    
    $ python3 -m pip install paramiko
    次に、いくつかのよく使われているssh登録の方法を紹介します。
    方法1:ユーザー名とパスワードに基づくsshclient方式で登録する
    その後、下記のコードを参考にして、Linux/OSXシステムの下で遠隔接続を行うことができます。
    
    import paramiko
    
    ssh = paramiko.SSHClient()
    #       know_hosts      
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    
    #     
    ssh.connect("xx.xx.xx.xx", username="root", port=22, password="you_password")
    
    #           
    ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("ls -l")
    
    #     
    print(ssh_stdout.read())
    
    #     
    ssh.close()
    方法2:ユーザ名とパスワードによるトラッピング方式で登録する
    方法1は、従来の接続サーバ、実行コマンド、オフの1つの操作であり、複数の操作は複数の接続が必要であり、[4つの痛み]を多重化することができない。
    コマンドの実行、ファイルのアップロード/ダウンロードなど、サーバーにログインして複数の操作を行う必要がある場合があります。方法1では実現できません。
    
    import paramiko
    
    #     
    trans = paramiko.Transport(("xx.xx.xx.xx", 22))
    trans.connect(username="root", password="you_passwd")
    
    #  sshclient    transport      trans
    ssh = paramiko.SSHClient()
    ssh._transport = trans
    
    #           
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("ls -l")
    print(ssh_stdout.read())
    
    #     
    trans.close()
    方法3:公開鍵に基づくSSHClient方式で登録
    
    import paramiko
    
    #      RSA    
    #               ,password      ,      password  
    pkey = paramiko.RSAKey.from_private_key_file('/home/you_username/.ssh/id_rsa', password='12345')
    
    #     
    ssh = paramiko.SSHClient()
    ssh.connect(hostname='xx.xx.xx.xx',
                port=22,
                username='you_username',
                pkey=pkey)
    
    #     
    stdin, stdout, stderr = ssh.exec_command('ls -l')
    
    #     stdout ,        stderr 
    print(stdout.read())
    
    #     
    ssh.close()
    方法4:鍵ベースのTransport方式で登録する
    
    import paramiko
    
    #      RSA    
    #               ,password      ,      password  
    pkey = paramiko.RSAKey.from_private_key_file('/home/you_username/.ssh/id_rsa', password='12345')
    
    #     
    trans = paramiko.Transport(('xx.xx.xx.xx', 22))
    trans.connect(username='you_username', pkey=pkey)
    
    #  sshclient    transport      trans
    ssh = paramiko.SSHClient()
    ssh._transport = trans
    
    #     ,       
    stdin, stdout, stderr = ssh.exec_command('df -hl')
    print(stdout.read().decode())
    
    #     
    trans.close()
    以上の4つの方法は、リモートログインサーバがコマンドを実行するのを助けることができます。多重接続が必要ならば、1回の接続で複数のコマンドを実行し、方法2と方法4を使用することができます。
    使用後は、接続をオフにしてください。
    sftpファイル転送を実現する
    同時に、paramikoはsshの完璧な解決策として、非常に専門的で、それを利用してsftpファイルの転送を実現することができます。
    
    import paramiko
    
    #      trans  #      transport  
    trans = paramiko.Transport(('xx.xx.xx.xx', 22))
    
    #     
    trans.connect(username='you_username', password='you_passwd')
    
    #       sftp  ,       
    sftp = paramiko.SFTPClient.from_transport(trans)
    
    #     
    sftp.put(localpath='/tmp/11.txt', remotepath='/tmp/22.txt')
    
    #     
    sftp.get(remotepath='/tmp/22.txt', localpath='/tmp/33.txt')
    trans.close()
    ここに来て、Paramikoはもう完勝しました。でも、まだ一つの痛い点があります。私達は多くのプラットフォームを話しています。つまりWindowsです。ここにいいことがあります。悪いことがあります。
    良いことは:paramikoサポートwindows
    悪いことはたくさんの複雑な準備が必要です。googleで解決してもいいです。でも、直接にやめてください。穴が深すぎます。

    4.最後に書く
    対照的に、いくつかの実例との展示を通して、Paramikoは専門的で、安心できるssh利器であることが分かります。個人的にはParamikoモジュールはオペレータ必学モジュールの一つだと思います。
    最後に、この文章があなたを助けてくれることを願っています。
    以上はPythonでサーバーにリモート登録する手順の詳細です。Pythonのリモートログインに関する資料は他の関連記事に注目してください。