2017/02/08

GAE/pyのプロダクションのDatastoreをdev_appserverにコピーする方法

ある程度運用しているGAEのDatastoreをまんまローカルにコピーして、dev_appserverで動かす方法。

0. remote_apiの設定

何はともあれremote_apiを使えるようにする必要がある。
app.yamlに下記を追加
builtins:
- remote_api: on

とりあえずデプロイ。デプロイしたアプリのバージョンをdefaultにする必要はない。
ここではバージョンを10として説明します。

1. Datastoreのダウンロード

下記のコマンドでDatastoreのエンティティをダウンロードする

% appcfg.py download_data --application=YOUR_APP --url=http://10-dot-YOUR_APP.appspot.com/_ah/remote_api --filename=datastore.sqlite

YOUR_APPはGAEアプリの名前。
--urlで指定する時、デプロイしたバージョンのサーバ(remote_apiが使えるサーバ)にアクセスする。
必要なkindだけをダウンロードしたい場合は--kindなどで指定できる。
datastore.sqliteというファイル名でダウンロードされる。ファイル名は任意。

2. dev_appserverにアップロード

dev_appserverを起動する。
% dev_appserver.py app.yaml
下記コマンドでdev_appserverに先ほどダウンロードしたdatastoreのデータをアップロードする。
% appcfg.py upload_data --application=dev~YOUR_APP --url=http://localhost:8080/_ah/remote_api --filename=./datastore.sqlite
applicationで指定する名前に注意。
アプリ名の前に「dev~」が付きます。
urlではdev_appserverのURLを指定する。
実行すると、アップロードが開始され、完了するとサーバのDatastoreがローカルに構築されている。

3. 401エラー

dev_appserverにデータストアのデータをアップロードすると、
Refreshing due to a 401
というエラーが表示され、dev_appserver側のログでも
INFO     2017-02-08 04:49:05,871 module.py:787] default: "GET /_ah/remote_api?rtok=584784529929 HTTP/1.1" 401 57
という401エラーが出る場合がある。
remote_apiがadmin権限でしかアクセスできないが、appcfg.pyの認証系がうまく動いていない場合に発生するっぽい。
ちょっと強引な方法だが、remote_apiのadminチェックを切ってしまえばOK。
まず、下記ファイルを開く。
${GCLOUD_ROOT}/platform/google_appengine/google/appengine/ext/remote_api/handler.py
その中に、def CheckIsAdmin(self)メソッドがあるので、そのメソッドの返り値を無条件でreturn Trueとする。メソッドの一行目にreturn TrueとすればOK。
def CheckIsAdmin(self)
    return True
注意)アップロード処理が終わったら、この修正をもとに戻しておくことをおすすめします。

4. おまけ

dev_appserverのdatastoreの保存先ファイルをバックアップしておくことで、いつでもデータストアを復元できて便利です。
たとえば本エントリーでdatastoreをアップロードし終わったら、そのファイルを保存しておき、いつでもその状態でdev_appserverを起動できます。
まずアップロードする前に下記手順でdev_appserverを起動します。
% touch datastore.db
% dev_appserver.py --datastore_path=./datastore.db app.yaml
そして、appcfg.pyを使ってデータストアのデータをアップロードします。
アップロードが完了したらdev_appstoreを停止し、datastore.dbをバックアップします。
% mv datastore.db datastore.master.db
今後、dev_appserverを起動するときに、以下の手順で起動すると、かならず元のdatastoreが復元されるので色々便利だと思います。
% cp datastore.master.db datastore.db
% dev_appserver.py --datastore_path=./datastore.db app.yaml