GoogleAppEngineでsocketが使えるようになったのは1年ぐらい前だった気がしますが、使ったことなかったので試してました。
Sockets Python API Overview | Python | Google Cloud Platform
まだプレビューリリースですね。
socketを使えるのならparamikoでSSH接続できたら面白いなーと思ってやってみたところ、そのままでは動かなかったのですが、少しコードを変更すれば動きました。
試したバージョンはPython 2.7, GoogleAppEngine SDK 1.9.5, paramiko 1.14.0です。
AppEngineで動くようにparamikoのコードを変更する
subprocessモジュールがAppEngineでは使えないので、importのところでこけました。ProxyCommandは使わないので、PopenとPIPEをNoneでとりあえず埋めときます。
paramiko/proxy.py:L24-25を変更
#from subprocess import Popen, PIPE Popen, PIPE = None, None
また、Transportクラスでsocketのタイムアウトが0.1秒に設定されてしまい、AppEngineだと「[Errno 11] Resource temporarily unavailable」のエラーとなってしまうので、タイムアウト時間を変更します。とりあえず10秒
paramiko/transport.py:L201
self.sock.settimeout(10)
これで動きました。
サンプルコード
main.py
import os import paramiko def app(environ, start_response): base_dir = os.path.dirname(os.path.abspath(__file__)) client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect( 'example.com', username='spam', key_filename=os.path.join(base_dir, 'secret.key')) stdin, stdout, stderr = client.exec_command('uname -a') start_response('200 OK', [('Content-type', 'text/plain')]) return stdout.read()
ホスト名、ユーザー名、鍵ファイルは自分のものを使用。paramikoと依存するecdsaモジュールはsys.pathの通っている場所に置いてます。
また、app.yamlでpycryptoを有効にしています。
雑感
Sockets APIはpaid appsでしか使えないのだけど、それは仕方ないかー。接続のところが遅いのはAppEngineの仕様なのかな。長時間つなぎっぱなしにできないし、bindして待ち受けることもできないので用途は限られる感じ。
とはいえできることの幅が広がったのはいい感じだなー。