管理ページを本番にもデプロイして、メンテナンスを楽にするぞえ


アドベントカレンダーが同日2つ入れてしまって焦っている大橋です。

ここ2年ぐらいはお仕事でGAE/Pyを触っています。
今までGAE/J、GAE/Goと触ってきて原点回帰のGAE/Pyなので色々思うところもありますが、やっぱりGAEって素敵だな、あれ俺SQLかけなくなっているんじゃないかな？、このアプリケーション無理してDatastoreにしなければよかったんじゃないかなって思う日々です。


さてサービスをGAEで作って運用しているとDatastoreを直接いじりたいことは多々あると思います。
そんな時皆さんはどのようにやっているでしょうか？

大きく分けて以下のような方法があると思います。

1. Cloud ConsoleのDatastore Viewerで修正する
2. Remote API経由でクライアントから叩く
3. 修正バッチをデプロイして叩く

どの方法も悪くは無いのですが、それぞれ問題点がありつらい気持ちになることがあります。

今回は1,2,3の問題をクリアした`google.appengine.ext.admin.application`について書きたいとおもいます。


## Datastoreのデータを修正する苦痛

以下は色々な恨みつらみを書いているだけなので読まなくてもいいとお見ます。

### Cloud ConsoleのDatastore Viewerで修正する場合

Cloud ConsoleのDatastore Viewerはかなり更新されてて、かなり多くのケースでデータを更新できるようになってきました。
ただGAE/Pyでndbを利用している場合や、独自ライブラリ、Goonなどを利用している場合、直接Datastore Viewerで更新してしまうと、 **memcacheのデータが更新されない** という問題があります。

この問題にぶち当たると、なかなか気がつくことができず、またmemcacheとDatastoreの間に差異がうまれ、障害を生むことが多々あります。

場合によってはmemcacheをすべてクリアする必要があり、相当めんどくさいです。

### Remote API経由でクライアントから叩く

[App Engine remote API](https://cloud.google.com/appengine/docs/python/tools/remoteapi)を利用することで自分自身のPCでコードを下記、直接実行することが可能です。

またRemote API Shellを利用すればiPythonの様な対話的にAppEngineとやり取りすることも可能です。

```
 >>> from google.appengine.ext import ndb
 >>>
 >>> # Fetch 10 keys from the datastore
 >>> ndb.Query().fetch(10, keys_only=True)
```

これはこれでかなり便利なのですが、頻繁にデータをやり取りする必要がある処理を書く場合、データの取得や書き込みなど、全てのRPCコールがクライアントからAppEngineのサーバへのHTTP通信となり、非常に遅いという問題があります。

またログ上も1つのRPCコールにつき一回HTTPリクエストが飛んでいてうざいことこの上ありません。

### 修正バッチをデプロイして叩く

大規模なモデルデータにプロパティを追加したりなどする場合は適当なTaskQueueを作って一気に処理することがあります。

正直デプロイがめんどくさすぎるので運用でやるぐらいの場合はやりたくありません。

## そこで`google.appengine.ext.admin.application`

### ローカルのAmdmin Server
ローカルでdev_appserver.pyを立ち上げた際に

```

INFO     2016-12-02 08:30:49,546 admin_server.py:116] Starting admin server at: http://localhost:8000
```
の用にadmin_server.pyが立ち上がっており、ここにアクセスすると管理ページが利用できます。
管理ページではローカルのDatastore、Memcache、Task Queueの状態や、メール受信のシミュレーションを行うことができます。

その中に「Interactive Console」と呼ばれるものがあり、直接Pythonコードを記述し、コードをサーバに送信、実行する事ができるます。

![Kobito.FlIaob.png](https://qiita-image-store.s3.amazonaws.com/0/2965/2af5f8d2-14d9-558b-03eb-d7c3314a5e18.png "Kobito.FlIaob.png")

ローカル環境でファイルにコードを書かずとも、簡単にコードを実行でき、メンテナンスやデバッグに利用することができるようになります。

### Adminページを本番環境でも動かす

`google.appengine.ext.admin.application`はこのローカルのAdmin Serverを本番環境でも利用できるようにしたもので、PythonのAppEngine SDK内に含まれています。

`google.appengine.ext.admin.application`を利用するにはapp.yaml内にルーティングを追加します。

```
- url: /adminapplication/.*
  script: google.appengine.ext.admin.application
  login: admin
```

なお必ず `login: admin`を忘れずに付けてください。
付け忘れると誰でも自分のGAE上で好きなコードを実行できるようになってしまいます。自己責任でやってください。

この状態でアプリケーションをデプロイすると、割り当てたパスでAdminページが表示できるようになります。

![Kobito.3NQ9jC.png](https://qiita-image-store.s3.amazonaws.com/0/2965/8d32df7f-65b7-e367-7768-e28ae25c5097.png "Kobito.3NQ9jC.png")

見た目が若干違うのは多分このAdminページのアプリケーションは古いまま更新されておらず、Adminサーバ側のみ更新されているからかなと思います。

このページ内にも「Intractive Console」が存在し、ローカル版同様に直接コードを記述し、実行することができます。

![Kobito.ZGst87.png](https://qiita-image-store.s3.amazonaws.com/0/2965/8dfd2774-e6c4-aa1b-ab67-b0e23f11278c.png "Kobito.ZGst87.png")


もちろん、自分のアプリケーション内で利用している、モジュールや、ライブラリは全て利用でき、ndbなども問題なく動きます。
メンテナンスがとても楽になりますね！


## まとめと注意点

`google.appengine.ext.admin.application`を利用すると本番サービスのメンテナンスがとても楽になります。
またちょろっとしたデータをcsvで出してほしいと言われたときとかも、print文などを使うと左側のテキストエリアに表示されるため、ここから簡単に抽出することができます。

ただ注意点がいくつかあります。
一つ目はこの仕組は通常のハンドラーと同じ仕組みなため、通常の60秒制限や、各種タイムアウトは同じ様に受けます。
大量のデータを更新する場合は注意が必要です。

二つ目は上にも書きましたが、どんなコードでも実行できてしまうためセキュリティには注意が必要です。必ず `login: admin`を指定するようにしましょう

三つ目は当たり前ですが、やらかしたコードを書いてしまうと、全てのデータが消えたりと、辛い目にあります。
何時でもちゃんとローカルで試してからコードを実行したり、指差し確認したり、復旧できる仕組みを用意しておくのが良いと思います。

やらかしたときは一瞬脳も消えた感じになります。

なお何かあっても責任は取れませんので自己責任で利用してください。

GAEの運用者が1秒でも早く帰れることを願っています。