基本情報
-
公式サイト
http://ethersheet.org/
-
ソースコード
https://github.com/ethersheet-collective/EtherSheet/
-
参考
http://kachibito.net/useful-resource/ethersheet
手順の概要は以下の通りです。
- ソースコードの取得
- ソースコードの修正
今回,Cloud Foundry 上で動作させるに当たって,2点ほど修正が必要だったので,それについて述べます - サービスの作成
本アプリは MySQL を使うので,MySQL サービスのインスタンスを作成します - アプリの push
今回は manifest.yml ファイルを使って push してみました
ソースコードの取得
$ git clone https://github.com/ethersheet-collective/EtherSheet.git
EtherSheet ディレクトリーに入ります。$ cd EtherSheet/
ソースコードの修正
本アプリを Cloud Foundry上で動作させるに当たり,実地検証の結果,ソースコードの修正が必要と判断しました。この部分の記事の書き方としては,大きく,
- (a) まず正しい手順を書き,その後失敗の経験に基づいた注意点を書く
- (b) 失敗した手順を書き,原因を解明して修正したあと,成功した手順を書く
今回の修正のポイントは,
- MySQLの接続情報を環境変数から取るようにする
- アプリが待ち受けるホスト/ポートの情報を環境変数から取るようにする
MySQLの接続情報を環境変数から取る
本アプリは,データベースの接続情報を設定ファイル (config.js) から取るようになっています。しかし, Cloud FoundryやHerokuのような PaaS では,データベースを service としてカジュアルに結合(bind)/切断(unbind)することを想定し,そうした情報は環境変数として与えられる造りになっています。これに合うよう,ソースコードを修正しました。実際の修正内容は以下の通りです。既存の動作を変えないよう,環境変数がある場合のみ上書きされ,それ以外は設定ファイルの値を使うようになっています。
$ git show 20f77d7
1commit 20f77d78c2079966dd6624b7abdca59705017f78 2Author: Noburou TANIGUCHI <taniguchi.noburou@lab.ntt.co.jp> 3Date: Mon Jun 8 12:35:16 2015 +0900 4 5 Get database connection credentials from DATABASE_URL env var 6 7 For easiness to run on Cloud Foundry / PaaS environment. 8 9diff --git a/lib/ethersheet_service.js b/lib/ethersheet_service.js 10index e527c0e..58aa2c4 100644 11--- a/lib/ethersheet_service.js 12+++ b/lib/ethersheet_service.js 13@@ -5,6 +5,7 @@ var uuid = require('node-uuid').v4; 14 var async = require('async'); 15 var async = require('async'); 16 var csv = require('csv'); 17+var url = require('url'); 18 var _ = require('underscore'); 19 var Sheet = require('./models/sheet'); 20 var SheetCollection = require('./models/sheet_collection'); 21@@ -15,12 +16,26 @@ var SheetCollection = require('./models/sheet_collection'); 22 var EtherSheetService = module.exports = function(config){ 23 var es = this; 24 es.config = config; 25+ 26+ /* for Cloud Foundry */ 27+ var dbUrl = url.parse(process.env.DATABASE_URL); 28+ if (dbUrl) { 29+ es.config.db_host = dbUrl.hostname; 30+ es.config.db_port = dbUrl.port; 31+ var path = dbUrl.path.slice(1).split(/[?#]/); 32+ es.config.db_name = path[0] 33+ var auth = dbUrl.auth.split(':'); 34+ es.config.db_user = auth[0]; 35+ es.config.db_password = auth[1]; 36+ } 37+ 38 events.EventEmitter.call(this); 39 this.connectionHandler = function(){}; 40 es.db = new ueberDB.database( 41 es.config.db_type, { 42 user: es.config.db_user, 43 host: es.config.db_host, 44+ port: es.config.db_port, 45 password: es.config.db_password, 46 database: es.config.db_name 47 });
アプリが待ち受けるホスト/ポートの情報を環境変数から取る
前項と同様に,本アプリでは,アプリが待ち受けるホスト/ポートの情報を設定ファイル (config.js) から取るようになっています。しかし Cloud Foundry環境では,アプリの起動・停止が簡単に行えるよう,アプリのインスタンスはコンテナー内で動作し,待ち受けポートも61001番以降から自動で採番したものを環境変数に入れるようになっており,ユーザーが指定できるようにはなっていません。そこで,アプリの待ち受けポートも環境変数から取れるよう,ソースコードを修正しました。
実際の修正内容は以下の通りです。前項と同様,既存の動作を変えないよう,環境変数がある場合のみ上書きされ,それ以外は設定ファイルの値を使うようになっています。
$ git show bf3e351
1commit bf3e3510bd6e8393a5d10e81427110e3f34ed493 2Author: Noburou TANIGUCHI <taniguchi.noburou@lab.ntt.co.jp> 3Date: Mon Jun 8 12:40:36 2015 +0900 4 5 Get host / port to listen from VCAP_APP_HOST / VCAP_APP_PORT env var 6 7 For easiness to run on Cloud Foundry / PaaS environment. 8 9diff --git a/lib/ethersheet_service.js b/lib/ethersheet_service.js 10index 58aa2c4..2efb0d5 100644 11--- a/lib/ethersheet_service.js 12+++ b/lib/ethersheet_service.js 13@@ -18,6 +18,8 @@ var EtherSheetService = module.exports = function(config){ 14 es.config = config; 15 16 /* for Cloud Foundry */ 17+ es.config.host = process.env.VCAP_APP_HOST || es.config.host || 'localhost'; 18+ es.config.port = process.env.VCAP_APP_PORT || es.config.port || 8080; 19 var dbUrl = url.parse(process.env.DATABASE_URL); 20 if (dbUrl) { 21 es.config.db_host = dbUrl.hostname;
サービスの作成
本アプリは永続化ストレージとして MySQL を使うので,MySQL サービスのインスタンスを作成します。今回利用した MySQL サービスは, cf-mysql-release を利用して構築しました。これは postgresql-cf-service-broker とは異なり,アプリのデプロイは全く関係ないので,今回構築方法等については触れませんが,記事化のご要望等あれば何か考えたいと思います。
サービス種別の一覧:
$ cf marketplace
Getting services from marketplace in org nota-ja / space 100 as nota-ja...
OK
service plans description
PostgreSQL Basic PostgreSQL Plan* PostgreSQL on shared instance.
p-mysql 100mb-dev, 1gb-dev A MySQL service for application development and testing
......
サービスの作成:$ cf create-service p-mysql 100mb-dev my4es
Creating service instance my4es in org nota-ja / space 100 as nota-ja...
OK
アプリのpush
これで準備が整ったので,いよいよアプリをpushしていきます。今回は Application Manifest ファイル (manifest.yml) を使って push してみました。
Cloud Foundryにアプリをpushする際には (例えば
cf push
コマンドのヘルプを見るとわかりますが) 非常に多くのオプションがあります。メモリ上限, ディスク上限, インスタンス数, ホスト名, ドメイン名, 起動コマンド, push時に起動するか,…, 等々。同じアプリをpushするとき,これらをpushの度に指定する面倒さを軽減するための機能が,Application Manifest ファイルです。先述したような設定をこのファイルに書いておくことで,同じ設定でpushを繰り返す場合は単に cf push
とするだけで済むようになります。今回使用した manifest.yml の内容は以下の通りです。
$ cat manifest.yml
---
applications:
- path: .
name: es
random-route: true
memory: 256M
instances: 1
services:
- my4es
このファイルがあるディレクトリーで cf push
を実行します。$ cf push
Using manifest file /home/nota-ja/workspace/100/EtherSheet/manifest.yml
......
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: es-inactive-fluffer.10.244.0.34.xip.io
last uploaded: Mon Jun 8 01:01:31 +0000 2015
stack: lucid64
state since cpu memory disk details
#0 running 2015-06-08 10:02:28 AM 0.0% 72M of 256M 0 of 1G
アプリが起動しました。ちなみに,上記の manifest.yml の記述は,だいたい以下の手順と等価です。
$ cf push es -p . --random-route -m 256m -i 1 --no-start
$ cf bind-service es my4es
$ cf restage
動作確認
アプリが無事起動したので,実際にブラウザーからアクセスしてみます。初期画面
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHhrVC6QodWL00SoxlEOGo5pP4SAJn5bZDdZVr9Fev92re3hwu5TiTFrpsv96mElvrr78sMJo53II7hlw_tCbIfzltkoqS-MoMqJ4rVm23y31hT4GEr0ON7wl80mALgfr6mOfyzHzhGVo/s320/003-initial.png)
GOTO SHEET
ボタンを押すと初期状態の spreadsheet に遷移します。spreadsheet の初期状態
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOJiCxDJ7E7iqKDcRZhCSFRFH0yJKiHoIlsMDvjXUgWRGXyRNNPApULzFpM8UAwPYy0vTxkKeEHqbEbm9JRbQ-CQ6TDyh4ZmvCUYO0uyRnwCcGSOifjjQNMq3Tzi3SieS3azUN6wIsUpc/s320/003-spreadsheet-initial.png)
セルに値を入力
A1 セルに123
を入力してみます。![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvnPk7-lXlYOH6JTFZm5oBCRGaxPzCwmMmrIh5_kkuQQL6z5tnGw7BJxDRoBrZ0kqQ9Xr9fnKEkt-KkO_JOMEKDst_XXtCDCy-WywsiTqPgcKI2nmge1Ems0c5HPCq8VfpO33ffnrjj2k/s320/003-input-into-cell.png)
合計関数
合計を取るsum
関数を A3 セルに入力してみます。![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinVWTr6h-chk9n2mn9nsn_MLrY5e7rFfuL4IRqFsQQLwH0MiPKq_rvbv9z6H5awi3w8JVlNAH-fHaDIN1L0z41QKmrlBwWyhGRD2Wa6dV31O4cYpI5ZEiR3wjistdIr5_L8NG7UIvLuS0/s320/003-input-sum-function.png)
↓
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi01b9yD_ELD9YkMgfErdjxM5F4XrnzVBRiy5XBLQ2-3BiBSska6jmKTaDzQLqltK4mYoWceiyGxqYvK2TUxOdqa3KUdR3eT6Z2CBQFnW_akoaUXH16dbuO2T3LpNnhBPq5Ik3gfAvLqsY/s320/003-sum-result.png)
正しい計算結果
579
が表示されました。FUNCTIONS ペインから関数を入力
左上の右側のボタンをクリックして,FUNCTIONS ペインを表示し,そこからsqrt
関数を選択してみます。![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqcofv-jlHjJ1yohk8QJx0Nz2DBiKPsZmy4YpFHOaGV62_fyfDMeJeF2R38zDM0gTOyubU-1TsX66xttY7-gLwIgxb-PYYTj3sQy2iCWvsqC7G-fYC6JWiuhtx8FqoMmXEN1p-TD1COpQ/s320/003-input-from-function-pane.png)
sqrt_def
という文字列が入力されました。入力された文字列を正しい関数名
sqrt
に修正し,A3 セルを引数に与えてみます。![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQPMOy2UXf0kv5CHprqJSWnFHj1hyphenhyphenv9x4ClnmYmFsw5CQGjWamxT_UR0dttI4_EO3idk0Gc12Q8MFMPCrJfK_f_HFnkBI_FUwwlRfNe1ZVIyDJhil2G5RLvof40MskfzbmVxoYZ1dctVY/s320/003-modify-sqrt-function.png)
↓
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHefrHWXWN93RF8Xd2pZmXUj18lp0hcc5YY1L-FZtG1oNfuQOvc9wVCbXpMi-2M9F0RENJvwCJVVKE3bK28eaxug8VUviEIjTL1UpMoJv6bP41A40HL8xiOloEhuEYTX_lFoQKaPHPTJs/s320/003-sqrt-result.png)
A4 セルに計算結果が表示されました。
SHEETS ペイン
左上の左側のボタンをクリックして,SHEETS ペインを表示させます。![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyYdqdRPxm9S3JB7iXBTkirUR6pMPe2lBBvHLO2l4RIz3MDlKsf10goW47Zv9cvb9c2yF9D4Sm9HMH9bTiUOW6GgjgO3prQ5ANr1lkrIjFTg8YOdvHJNb9HibrAI7o9JKD7vF_82Qefew/s320/003-sheets-pane.png)
新シートの作成
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-RJH2KB6GHhmkT5rY1Frb1bmXLeE5HRaf0OR26TWbUCWz7sTK_OZcQ8FKPUGKUXlz45PyWSvuGdsYYIJyxI8zMdNLcLdFrIc0718p18IAgIdMmEVgygE4XANRcTM42XYvDIRo0D_PTdg/s320/003-new-sheet.png)
newSheet
ボタンをクリックし,新シートを作成しました。新しいシートは空です。
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5VcBtJr7Z5AJ-VJ8o6qMdyQ4GIotY0dqp7h_Ri7JTeFl2SkKslyy2V209_jMJUCrQzTbmVld6qb5AWlO-rOzpijyYlaCiN56ZsZgs332irSE6Ps_zuqEPW2xt1fLLsXmRHRkkevucKmE/s320/003-sheet2.png)
CSVのエクスポート
exportCSV
ボタンをクリックすると,生のCSVファイルがブラウザー上に表示されます。![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtjTT7hzDXOCkFf3ldq5lOogK_z5a66lvG6dwexAZeytkDdy0eVR4f9kWp08iz5A2DTIotRKDMZqDlFkCtY-zkMfcKr0ZI8rxFACzsaGkDmNZY1sbKy0fCyWsy5CyjZQGQ5He47t733eY/s320/003-export-csv-result.png)
ここでブラウザーのメニューから
保存
を実行すると,保存ダイアログが出てくるので,保存します。![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfM38bTRAAQkV1GKBJ0_aP5L-nbCFc-s-WGaMQ9Xi8D5IRCbLxTxa2mcU256ygs28P4V9GjFVXSlTqQI9Efr7sOqId-YIP0LoczPrepvEMftGGHPil2tks676FeUTJ_G0rjb1ga6ClDDE/s320/003-save-exported-csv.png)
CSVのインポート
Sheet2 に,先ほどエクスポートしたCSVをインポートしてみます。importCSV
ボタンをクリックすると,インポート・ダイアログが表示されます。![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL4ys6HhPMDYZ1I7zY92vQBkJK19BNe1SbVwiscSW9DQlDOfC4B0bEPAzi4Rm5_ZiA0OJOkrhUoQ5ppyLjOedkp1iwyKKh3mMI10vL0HzczkgWpvP9k08ewmBKuJt1T66CzTk7Nxuakxc/s320/003-importing-csv.png)
「ファイルを選択」をクリックすると,ファイル選択ダイアログで先ほど保存したCSVファイルを選択すると,インポートの準備が整います。
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL4ys6HhPMDYZ1I7zY92vQBkJK19BNe1SbVwiscSW9DQlDOfC4B0bEPAzi4Rm5_ZiA0OJOkrhUoQ5ppyLjOedkp1iwyKKh3mMI10vL0HzczkgWpvP9k08ewmBKuJt1T66CzTk7Nxuakxc/s320/003-importing-csv.png)
Upload
ボタンをクリックすると,インポートされる…はずですが,エラーが表示されました。![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_3LBlbPJIldz8Zbwd4T7mHCKsKTm47n6kyfXXjbFMkuWchNiRwR6T3Vog5fxSsAg3biF_Si16NbdxdqO1dPesnqwX576q-h8kFuoXxqZKqOI4GT0p3vc4atMRgCWyG_iKzsrRa8FtHjY/s320/003-failed-importing-csv.png)
この時のアプリのログは以下のようになっていました。
2015-06-08T10:36:55.40+0900 [App/0] OUT POST /HRgZgHUlR5nvSmb74kT5/pubsub/589/5rukm6ta/xhr 0ms (unfinished)
2015-06-08T10:36:58.15+0900 [App/0] ERR /home/vcap/app/lib/ethersheet_service.js:161
2015-06-08T10:36:58.15+0900 [App/0] ERR csv().from(data.toString())
2015-06-08T10:36:58.15+0900 [App/0] ERR ^
2015-06-08T10:36:58.15+0900 [App/0] ERR TypeError: object is not a function
2015-06-08T10:36:58.15+0900 [App/0] ERR at EtherSheetService.createSheetFromCSV (/home/vcap/app/lib/ethersheet_service.js:161:3)
2015-06-08T10:36:58.15+0900 [App/0] ERR at /home/vcap/app/lib/server.js:86:10
2015-06-08T10:36:58.15+0900 [App/0] ERR at fs.js:271:14
2015-06-08T10:36:58.15+0900 [App/0] ERR at Object.oncomplete (fs.js:107:15)
今回全く触っていない部分のエラーなので,未完成なのかもしれません。ブラウザーの「戻る」ボタンをクリックすると,接続エラー画面が。
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOvNwD6m-sqbfIAH1Utwp1k0vN7jd5wCn_LwldeM7xBw0Z4ptpRyMa44LkYbDSAB8ZjZgBmpvAReeTAYEBxL7ZUpFSDfdBnxNG6Y7L2v17IAREFlyZyc-AA5E0Mwq6g-DQeOsLmnt6FKw/s320/003-connection-lost-dialog.png)
指示通りリロードしてみましたが,
502 Bad Gateway
の文字が。![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmB1297Wc4TU-Hn3rCi4BTXjXmev8X8023kd3QuL4MC3sPSBq0QQ6AKS2I8AZrX6DRC0jaT0j2o-OyFso3D6hG2N2vgyuV0Xedspxs4Odew2tNVuzC_05E-ZgmmP5x9RDee9wFnF-HUZU/s320/003-bad-gateway.png)
仕方ないのでアプリを再起動してみます。
$ cf restart es
Stopping app es in org nota-ja / space 100 as nota-ja...
OK
Starting app es in org nota-ja / space 100 as nota-ja...
0 of 1 instances running, 1 starting
1 of 1 instances running
App started
OK
App es was started using this command `npm start`
Showing health and status for app es in org nota-ja / space 100 as nota-ja...
OK
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: es-inactive-fluffer.10.244.0.34.xip.io
last uploaded: Mon Jun 8 01:01:31 +0000 2015
stack: lucid64
state since cpu memory disk details
#0 running 2015-06-08 10:38:34 AM 0.0% 73.1M of 256M 0 of 1G
無事再起動しました。先ほど入力したのシートの URL にアクセスしてみると…。
![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLzdUQQOAgrMjXG1THzEe92fG4W-gr4igz__FPiUzDpLA5O51fcRAYl2wv_vSMJJbQQw44HCY96jz2Ros3IXgvF5uLHDP7bkd3__j6cs4u1PAKz-OHjPowz1pj0Rsrk6tXg9k7qDIn5AU/s320/003-status-after-restart.png)
正常に表示され,データも残っていました。
以上で一通りの動作確認は終わりです。
今回使用した環境
- cf-release (v194)
https://github.com/cloudfoundry/cf-release/tree/v194
( https://github.com/cloudfoundry/cf-release/tree/345a8b3e1ea0005a3e9fced13f0bf6fa6f7ad981 ) - bosh-lite
https://github.com/cloudfoundry/bosh-lite/tree/01db9da7b4122f7d02858d92e0fe938e91256649 - CF CLI (v6.11.3-cebadc9-2015-05-20T19:00:58+00:00)
https://github.com/cloudfoundry/cli/releases/tag/v6.11.3 - cf-mysql-release (v16)
https://github.com/cloudfoundry/cf-mysql-release/tree/v16
( https://github.com/cloudfoundry/cf-mysql-release/tree/63f0bc3914914ce469c80df07c9fa49c5b836f11 ) - EtherSheet
https://github.com/ethersheet-collective/EtherSheet/tree/76a79e12f25ec9864b5078e6f4a44517c29cf12b