本番のCloud Datastoreのデータを、ローカル環境にインポートする

Google App Engine(GAE)で動作しているアプリケーションがあります。
DBとしてCloud Datastoreを利用しており、開発環境を一新するにあたって、本番のデータをローカルでもそのまま使おうと思いました。

以前 https://noboru.hatenablog.jp/entry/20130212/1360679541 を書いていましたが、いろんなものがバージョンアップされていたので、最新の方法でやってみようと思います。

## 前提

Cloud Datastoreにデータが溜まっていること。
ローカルでは、 `dev_appserver.py` を利用していること。
`gcloud` などのツールが設定済みで、対象のプロジェクトに接続可能なこと。

## データのエクスポート
公式： https://cloud.google.com/datastore/docs/export-import-entities?hl=ja#starting_managed_export_and_import_operations

まずは、Cloud Datastoreの情報をエクスポートします。
エクスポート先として、Cloud Storageを指定する必要があるので、バケットを作成しておきます。
（今回は、いつの間にかあったものを利用しました。GAEの環境と同時に作成された？）

バケット名： `my-android-server.appspot.com`
保存先フォルダ： `datastore`

```bash
gcloud datastore export --namespaces="(default)" gs://my-android-server.appspot.com/datastore
```

これにより、Cloud Storageの対象のフォルダに、
1つの `datastore.overall_export_metadata` ファイルと、
`default_namespace` フォルダに含まれる大量の `output-0` のようなバイナリファイルができます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/8708/d0e73c5a-81f7-8a36-5bfd-8270ebb720a7.png)


## データをローカルにダウンロード
公式: https://cloud.google.com/storage/docs/gsutil/commands/cp

次のインポートでは、ローカルのデータを利用するため、一旦ローカルにデータを持ってきておきます。
大量にファイルがあるのですが、Webのダッシュボードからは一括でダウンロードする手段が見あたらなかったので、 `gsutil` を利用してダウンロードします。

```bash
gsutil cp -r gs://my-android-server.appspot.com/datastore .
```

これにより、カレントディレクトリに `datastore` ディレクトリが作成され、配下のファイルもダウンロードされます。

## ローカルサーバの起動
公式: https://cloud.google.com/appengine/docs/standard/python/tools/using-local-server

Google App Engineのローカル開発環境を立ち上げるため、 `dev_appserver.py` を起動します。

```bash
dev_appserver.py app.yaml --datastore_path=`pwd`/database/db.datastore -A my-android-server --support_datastore_emulator True
```

この際に、 `--datastore_path` を指定しておくことで、ファイル位置を指定しておきます。（削除など
また、 `-A` でAPP_IDを指定しておかないと、次のcurlで指定するPROJECT_IDがうまく指定できないようです。

起動時のログで、下記のようにCloud Datastore emulatorのアドレスが表示されます。

> INFO     2019-03-09 04:51:02,232 datastore_emulator.py:155] Starting Cloud Datastore emulator at: http://localhost:16895

## ローカルのDatastoreにデータをインポート
公式: https://cloud.google.com/datastore/docs/tools/emulator-export-import

https://cloud.google.com/datastore/docs/reference/admin/rest/v1/projects/import
これと同じものが実装されているようです。

```bash
curl -X POST "localhost:16895/v1/projects/my-android-server:import" -H 'Content-Type: application/json' -d '{"inputUrl":"datastore/datastore.overall_export_metadata"}'
```

ポートは、起動時に表示されていたCloud Datastore emulatorのポートを指定します。
`inputUrl` の指定は、相対パスで良いようです。
`PROJECT_ID` として、サーバ起動時に `-A` として渡していた `APP_ID` を指定します。

レスポンスとして、下記のような結果が返ります。

```json
{
  "name": "projects/my-android-server/operations/72cc047a2c254d85b703adb6ed5ac35f",
  "metadata": {
    "@type": "type.googleapis.com/google.datastore.admin.v1.ImportEntitiesMetadata",
    "common": {
      "startTime": "2019-03-09T05:01:28.442Z",
      "endTime": "2019-03-09T05:01:37.128Z",
      "operationType": "IMPORT_ENTITIES",
      "state": "SUCCESSFUL"
    },
    "entityFilter": {
    },
    "inputUrl": "datastore/datastore.overall_export_metadata"
  },
  "done": true,
  "response": {
    "@type": "type.googleapis.com/google.protobuf.Empty"
  }
}
```

（ちなみに、 `PROJECT_ID` の指定が間違っていても `"state": "SUCCESSFUL"` となりますが、次の確認の部分で表示されない状態になります。）

## 確認

http://localhost:8000/datastore をブラウザで開いて、本番と同じデータが表示されれば成功です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/8708/5ab4f83b-a54f-69cb-5fec-f6d9e40adcfb.png)


## 参考

https://qiita.com/aql/items/9754b23a7d23544b1c10