【エラー解決】Pythonでpysftp(SFTPファイル転送)を使用してWEBサーバーにファイル転送する

シェアする

スポンサーリンク
pythonでsftpによるファイル転送プログラミング

Tdnetを使用したネットネット株(割安株)の一覧をXServerのサーバー上のフォルダに自動的にファイル転送したかったので、覚書。(python pysftp(paramiko) install & example)

環境

OS: Max OS X Yosemite MacBook Air (11-inch, Mid 2011)
python 2.7
転送先 Xserver

brewをインストールしていないので、macportsを使用している。このあたりは管理環境が違うとうことぐらいでよくわかっていない。





pysftpのインストール

Pythonで使用するライブラリーpysftpとは、PythonでのSSH接続とSFTP転送をサポートするライブラリーparamikoをラップし、簡単にSFTP操作を実現するラッパーとのこと。

sudo easy_install pysftp

ファイル転送プログラム

Python/SFTPファイル転送を参考に実行テスト。

しかし、

pysftp.Connection実行時にエラー

#Traceback (most recent call last):
#  File "..../pysftp-test.py", line 16, in <module>
#    sftp = pysftp.Connection(HOST, username = USER, port = PORT, private_key_pass = PASS_WORD, private_key = PRIVATE_KEY_FILE)
#  File "build/bdist.macosx-10.10-intel/egg/pysftp/__init__.py", line 132, in __init__
#  File "build/bdist.macosx-10.10-intel/egg/pysftp/__init__.py", line 71, in get_hostkey
#paramiko.ssh_exception.SSHException: No hostkey for host xxxxxx.xserver.jp found.
#Exception AttributeError: "'Connection' object has no attribute '_sftp_live'" in <bound method Connection.__del__ of <pysftp.Connection object at 0x10d59aa90>> ignored

上記のエラーが発生する。

解決方法

stackoverflowのpysftp — paramiko SSHException, Bad host key from serverを参照すると

This seems to be some sort of bug with the pysftp wrapper… I’m not sure. Reverting to native paramiko got me connected just fine, so I’m going with that for now. Current working code:

rsa_key = paramiko.RSAKey.from_private_key_file('~/.ssh/the_key', password='myPassword')
transport = paramiko.Transport((inventory[0],8055))
transport.connect(username='theUser', pkey=rsa_key)
sftp = paramiko.SFTPClient.from_transport(transport)
print sftp.listdir()

pysftp.Connectionを使用せずに、とりあえずparamikoを直接使用すれば、動くよと。まぁ、根本的な解決ではないけどファイル転送できる目的が達成できればいいよね。

rsa_key = paramiko.RSAKey.from_private_key_file(PRIVATE_KEY_FILE, password=PASS_WORD)
transport = paramiko.Transport((HOST,PORT))
transport.connect(username=USER, pkey=rsa_key)
sftp = paramiko.SFTPClient.from_transport(transport)

私の場合は、Python/SFTPファイル転送を参考にしていたので、上記のように変更。

そして、SFTPによるファイル転送を確認できました。

以下sftp

#!/usr/bin/python
# -*- coding: utf-8 -*-

import paramiko

HOST = 'xxxxx.xserver.jp' #ホスト名(グローバルIPでもOK)
PORT = 10022 #SSHポート番号
USER = 'xxxxx' #接続先のユーザ名
PASS_WORD = 'xxxxx' #秘密鍵のパスフレーズ
PRIVATE_KEY_FILE = '/xxxx/xxxxx/.ssh/id_rsa' #接続元の秘密鍵ファイル
SERVER_ASSETS_DIR = '/home/xxxxx/xxxx.xxx/public_html/';

#pysftpを使用せず、直でparamikoを使用する
rsa_key = paramiko.RSAKey.from_private_key_file(PRIVATE_KEY_FILE, password=PASS_WORD)
transport = paramiko.Transport((HOST,PORT))
transport.connect(username=USER, pkey=rsa_key)
sftp = paramiko.SFTPClient.from_transport(transport)

sftp.chdir( SERVER_ASSETS_DIR )    #接続先の作業ディレクトリを変更
print sftp.listdir() #接続先のファイル/ディレクトリのリストを返す
print sftp.getcwd()  #現在の作業ディレクトリを返す
sftp.put(
	'/xxxx/result.html', #転送元のローカルファイルを指定
	SERVER_ASSETS_DIR +'/result.html'     #転送先のファイルを指定
)

sftp.close()

opensslのアップデート

pending 気が向いたら、調べて追記する(これは未解決)

opensslのバージョンが 0.9.8と古いversionだったらしく、opensslのアップデートをbrewを使わずmacportsのまま対応する方法を調べる。

“You are linking against OpenSSL 0.9.8, which is no longer ”
RuntimeError: You are linking against OpenSSL 0.9.8, which is no longer support by the OpenSSL project. You need to upgrade to a newer version of OpenSSL.

ファイル転送プログラムのpysftp.Connection実行時に上記のエラーが表示。しかし、pysftpをやめてparamikoをそのまま使用するだけで気にしなくてよかったのかもしれない。セキュリティ的な問題はあるだろうけど。

Python and OpenSSL version reference issue on OSX

export CRYPTOGRAPHY_ALLOW_OPENSSL_098=1

This appears to be a recent check of the hazmat cryptography library. You can see the source code at: https://github.com/pyca/cryptography/blob/master/src/cryptography/hazmat/bindings/openssl/binding.py#L221

The …ALLOW_OPENSSL… environment variable downgrades the error to a deprecation warning, if you are willing to take the risk. I also ran into this on OSX in just the past day, so something changed recently.

に記述がある通り、実行する前にexportしたら通るようになるんだけど、古いバージョンのまま実行されてしまって0.9.8を無視じゃなくて許可・・・なのでセキュリティに問題あるんだろうな・・・

でも、現状の環境だとこれ使わないとopensslアップグレードしてくれってメッセージが出る。一応、macportsのパスから引張てきてopenssl versionやsudo python -c “import ssl; print ssl.OPENSSL_VERSION”でも最新のほう参照するようになったけど、macportsのパスからデータ持ってきただけなので、最新のopensslを参照するようにするには、さらにpython自体のビルドし直しとか必要なんかな。

error: