IBM Cloud(旧bluemix)のnode-redのソースコード自動バックアップShellScript

#背景
node-redはブラウザ上で全て作業出来るので非常に便利ですが、反面、ソースコードがぐちゃぐちゃになってしまった時、あんまりにも酷い（インスタンスのメモリに不釣りあいな）処理を入れすぎて全く上がって来なくなっちゃったよぅ、、といった際にどうやって戻せば良いんだろうとドキドキする事があります。

なので、気休め程度にソースコードを別の場所に保管しておこうというのが趣旨です。

---

#前提
- JSONをパースする為の`jq`が動く事
- bashが動く事（というかMac前提です）
- curlが動く事
- gzipが動く事
- IBM Cloudのnode-redが動いている事
- ShellScriptをCron等で動かす事ができる

---

#全体的なお話
---

##node-redのソースコードはどこにあるか？
それは、node.jsに関連付けられているcloudantの中の、noderedというデータベースの中の、xxxxxxx/flowにJSON形式で入ってます。
なので、このShellScriptではそこを純粋にcurlで取得し、rev（リビジョン＝第何版なのか）の内容如何で保存したりしなかったりします。

---

実際に見たい場合は、ダッシュボードから自分のCloudantを開いて、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/116534/ad505e7d-34ad-0081-406c-1e25a34ce591.png)
こんな画像があるはずなのでポチってください。そして
![image.png](https://qiita-image-store.s3.amazonaws.com/0/116534/91a8dd0c-47fa-e4e8-5224-b0f2de881e2d.png)
このデータベースマークをポチって一覧されるデータベースのnoderedを見ればわかります。

---


##どうやってバックアップするのか
今回のShellScriptでは上述の通り、noderedの中のxxxxxxx/flow（xxxxxはアプリ名）にcurlでアクセスし、取得されたJSONの`.flow`のみをOS上のファイルとして保管し、圧縮かけます。

---


##どうやってリストアするのか
今の所、手動で頑張る仕様です。
保存されたJSONを解凍してエディタで開いてコピーし、cloudantのnoderedデータベースのxxxxxx/flowを開きます。(xxxxはアプリ名）
そして、.flowの中身をそっくり入れ替えます。（
入れ替えたらSaveChangesし、Node-redのインスタンスを再起動します。
普通に上がってきたらこれ幸いです。

---

###リストア時のコツ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/116534/8845d8c9-8b1d-d625-35ad-e861774b2d6b.png)
上記の`flow`の行番号が表示されている箇所の右隣の▼をクリックすると、トグルが閉じて配列のカッコだけが表示されます。下の様になります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/116534/f7d8d617-3d65-657b-70f4-8e42550d2f94.png)
そこを配列のカッコ［］を丸ごと選択してペーストすると間違えにくいと思います。

---


##リストアしても戻らないもの
Node-redのブラウザ上のエディタで編集したソースコード以外は全く戻りません。Node-redの細かい設定やエディタのパスワードなどは対象外です。
それらは別途管理が必要です。

---


#実装に必要なもの
- Node-redにバインドされているCloudantのサービス資格情報のurlの項目
- ディレクトリ構成は以下の様にする設計です。
    - cloudant_flow_monitor
        - bin
            - ここにShellScriptを配置します。ShellScriptは対象のアプリ毎に作成してください。
        - data
            - ここにフォルダが自動作成され、その配下にgzipファイルが置かれます。
        - etc
            - ここにアプリ毎の設定ファイル(最後のrevの内容）が自動的に置かれます。

---

##ShellScript
以下のスクリプトをbinの下においてください。ファイル名はアプリ名.shあたりにすると良いかもですね。

```
#!/bin/bash

APPL_NAME="HOGEHOGE_APP"
URL="https://XXXX:YYYY@ZZZZ-bluemix.cloudant.com/nodered/AAAAAA%2Fflow"

DIR="`dirname "$0"`"
cd "$DIR"

DATADIR="../data/${APPL_NAME}"
LASTFILE=../etc/${APPL_NAME}_last_rev.txt
LAST_REV=`cat $LASTFILE`

########

JSON=$(curl -s -m 10 -X GET $URL )
RC=$?

if [ $RC -ne 0 ]; then
# NG case
  echo "ERROR:RC=$RC, message=$JSON"
  exit $RC
else
# OK case
  #echo "OK, RC=$RC, message=$JSON"
  REV=$( echo $JSON | /usr/local/bin/jq ._rev )
  echo "_rev=$REV"
  if [ "$REV" != "$LAST_REV" ] ; then
     ##updated case
     osascript -e 'display notification "Flowが更新されました"  with title "Cloudant monitor"'
     if [ ! -d "$DATADIR" ]; then
         mkdir "$DATADIR"
     fi
     VER=$( echo $REV| sed "s/.\([0-9]*\)-.*/\1/g" )
     echo $REV > $LASTFILE
     FILE="${DATADIR}/${VER}_`date "+%Y%m%d_%H%M%S"`.JSON"
     echo $JSON | /usr/local/bin/jq .flow > $FILE
     gzip $FILE
     exit 0
  else
     ##same rev case
     #echo "same"
     exit 0
  fi
fi

```

---


###スクリプト内のurlについて

`https://XXXX:YYYY@ZZZZ-bluemix.cloudant.com/nodered/AAAAAA%2Fflow`

`https://`から`cloudant.com`までの間は、サービス資格情報で提供されているurlの項目まんまですのでコピペしてください。
その後の`/nodered/`は固定で、`AAAAAA%2Fflow`の箇所はデータベース内の`アプリ名/flow`という文書名を指定する為の内容です。その為、noderedデータベース内で表示される該当文書から`/flow`を除いた内容（アプリ名になるはずです）を記載ください。

---

###スクリプト内のAPPL_NAMEについて
これはディレクトリ名や設定ファイル名で使われますので適宜指定してください。
個人的には、スペースやハイフン、変な記号などは含まない値にする方が誤作動がなくて良いと思います。(例：hogehoge_app_nodered）

---

#動かすためには
スクリプトのパーミッションで実行権限をつけた後にcron等で自動実行させてください。
私は5分毎に実行させているので
`*/5 * * * * "/script/path/bin/hogehoge_app_nodered.sh" > /dev/null 2>&1`
の様に指定しています。パスは適宜置き換えてください。

---
#実行時の挙動

---

##更新があった場合
- Macのポップアップで**Flowが更新されました**と表示されます。
- これが嫌な人はスクリプトの`osascript`で始まる行をコメントアウトして下さい。


---

##更新がない場合
- 何も表示されません。私は5分毎実行なので、いちいち何か言われても陳腐化してしまうのであえて何も出しません。
- 欲しい人は`##same rev case`の辺りを適当にカスタマイズして下さい。

---

#運用上の注意点
- ただダラダラと更新された内容を保管するだけですので、適宜ハウスキープ（古いものの捨てる処理）などは検討下さい。
- どの版がどんな内容なのかも、この仕組みでは全くわかりません。ファイル名で時間がわかる程度です。内容の管理を行いたい場合は別途検討下さい。

---

#以上です。
もっとエレガントな管理方法がある方は教えて欲しいです。。
ありがとうございました。