LoginSignup
0

More than 1 year has passed since last update.

posted at

updated at

CloudFoundry ランタイム表示画面を Node-RED で作る

この記事は IBM Cloud Advent Calendar 2020 11日目の記事です。

Cloud Foundry API を利用して、IBM Cloud Foundry のランタイム情報を表示する画面の作成手順をご紹介したいと思います。すでに非推奨な、古い手順になってしまいますがご了承ください…

ページ最下部に フローの JSON を掲載しております。このページでは処理の流れやソースコードを解説しますので興味がある方はフローをインポートして実行してみてください。

「こうやればもっとスマートだよ」 といったノウハウがあればコメントいただけると嬉しいですっ!

IBM Cloud Foundry のランタイム画面

image.png
複数の Cloud Foudry アプリを実行しているとき、各アプリの状況を切り替えて表示するのが少し手間だと感じたのでお手製のランタイム画面を作成してみました。

お手製 ランタイム画面

image.png
上部ドロップダウンで Cloud Foundry アプリを選択すると、現在の状況が表示されます。

フローの全容

Cloud Foundry 認可フロー

IBM Cloud Foundry アプリの一覧や詳細情報を取得するために、認可トークンを取得するフローをサブフローで用意しました。
image.png

認可用のエンドポイントURL取得

以下のAPIから認可用APIのエンドポイントを取得します。

https://api.ng.bluemix.net/v2/info

認可API呼び出し

認可APIを呼び出し、トークンを取得します。(IBM Cloud のユーザ/パスワードを埋め込んでます…)

トークン取得
msg.url = msg.payload.authorization_endpoint ;
msg.url += "/oauth/token";
msg.method = "POST";
//(補足) Y2Y6は、username:cf (passwordなし)をBase64でエンコードしたものになります。
msg.headers = {
    'Authorization': "Basic Y2Y6",
    "Content-Type": "application/x-www-form-urlencoded"
};
msg.payload = {
    'grant_type': "password",
    'username'  : [IBM Cloud ユーザ名],
    'password': [IBM Cloud パスワード],
    'response_type' : 'token'
};
return msg;

メインのフロー

image.png
Node-RED 起動時に、IBM Cloud Foundry のアプリ一覧を取得し、ドロップダウンにGUID をセットします。

ドロップダウンの値が変化すると、選択されたアプリの詳細情報を取得して、UI の Gauge に値をセットします。

Cloud Foundry アプリ一覧取得

認可トークンをヘッダにセットして、アプリ一覧取得のAPIを呼び出します。

AppList取得
msg.url = "https://api.ng.bluemix.net/";
msg.url += "/v2/apps";
msg.method = "GET";
msg.headers = {
    'Authorization': msg.cfAuth.token_type + " " + msg.cfAuth.access_token,
    "Content-Type": "application/x-www-form-urlencoded"
};
msg.payload = {
};
return msg;

ドロップダウン用配列作成

アプリの詳細を取得するためには 固有の GUID が必要なので、ドロップダウンで選択できるように配列に格納しておきます。

ドロップダウン用配列
var ret = [];
ret.push({"未選択" : ""});
msg.payload.resources.forEach(x =>
{
    var itm = [];
    itm[x.entity.name] = x.metadata.guid;
    ret.push(itm);
});

msg.options = ret;
return msg;

Cloud Foundry アプリ詳細取得

ドロップダウンで選択された GUID を使用して、アプリの詳細情報を取得します。

App詳細取得
msg.url = "https://api.ng.bluemix.net/";
msg.url += "/v2/apps/" + msg.guid + "/stats" ;
msg.method = "GET";
msg.headers = {
    'Authorization': msg.cfAuth.token_type + " " + msg.cfAuth.access_token,
    "Content-Type": "application/x-www-form-urlencoded"
};
msg.payload = {
};
return msg;

取得した値の加工

使用メモリ量やディスク量は バイト単位 になっていて見づらいので、メガ単位 にします。

ここでは、change ノードJSONata を使ってみます。

メモリ使用量
メモリ使用量
$round(payload.stats.usage.mem / 1000000, 2)

image.png

ディスク使用量
ディスク使用量
$round(payload.stats.usage.disk / 1000000, 2)

image.png

CPU 使用量

CPU 使用量はパーセンテージ で表示したいので、少し違う加工をします。

CPU使用量
$round(payload.stats.usage.cpu * 100, 3)

image.png

こだわりポイント

この画面は、

  • 画面の初期化(アプリ一覧取得)
  • ユーザ操作待ち
  • 操作後の結果表示

という3つの状態を持っているので、画面下部に状態を表示するエリアを設けています。

image.png

枝分かれしたフローを接続し、状態に応じたメッセージを表示するようにしています。
image.png

今回のフロー

メインフロー

[{"id":"ea4953fa.d6725","type":"subflow","name":"CF認可","info":"","category":"","in":[{"x":50,"y":30,"wires":[{"id":"3827a45a.128e3c"}]}],"out":[{"x":700,"y":240,"wires":[{"id":"8f9021c2.dcc","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"42036e2f.e65ce","type":"function","z":"ea4953fa.d6725","name":"トークン取得","func":"msg.url = msg.payload.authorization_endpoint ;\nmsg.url += \"/oauth/token\";\nmsg.method = \"POST\";\n//(補足) Y2Y6は、username:cf (passwordなし)をBase64でエンコードしたものになります。\nmsg.headers = {\n    'Authorization': \"Basic Y2Y6\",\n    \"Content-Type\": \"application/x-www-form-urlencoded\"\n};\nmsg.payload = {\n    'grant_type': \"password\",\n    'username'  : IBM Cloud のユーザ名,\n    'password': IBM Cloud のパスワード,\n    'response_type' : 'token'\n};\nreturn msg;","outputs":1,"noerr":14,"initialize":"","finalize":"","x":420,"y":120,"wires":[["56819ad7.db63c4"]]},{"id":"56819ad7.db63c4","type":"http request","z":"ea4953fa.d6725","name":"認可エンドポイントに要求","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","x":500,"y":160,"wires":[["8f9021c2.dcc"]]},{"id":"3827a45a.128e3c","type":"http request","z":"ea4953fa.d6725","name":"認可エンドポイント取得","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://api.ng.bluemix.net/v2/info","tls":"","persist":false,"proxy":"","authType":"","x":190,"y":80,"wires":[["42036e2f.e65ce"]]},{"id":"8f9021c2.dcc","type":"change","z":"ea4953fa.d6725","name":"認可情報確保","rules":[{"t":"set","p":"cfAuth","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":220,"wires":[[]]},{"id":"194aa920.eaa857","type":"comment","z":"ea4953fa.d6725","name":"出力は msg.cfAuth","info":"","x":630,"y":280,"wires":[]},{"id":"c65f47d8.d266c8","type":"tab","label":"RestartSequence","disabled":false,"info":""},{"id":"2ef71c61.3e4684","type":"inject","z":"c65f47d8.d266c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"","topic":"","payload":"reboot","payloadType":"str","x":110,"y":60,"wires":[["6bd77466.0457ec","c68af762.6f8ed8"]]},{"id":"823c481.6d530b8","type":"comment","z":"c65f47d8.d266c8","name":"https://apidocs.cloudfoundry.org/247/","info":"","x":140,"y":20,"wires":[]},{"id":"7a1374ba.156aec","type":"function","z":"c65f47d8.d266c8","name":"AppList 取得","func":"msg.url = \"https://api.ng.bluemix.net/\";\nmsg.url += \"/v2/apps\";\nmsg.method = \"GET\";\nmsg.headers = {\n    'Authorization': msg.cfAuth.token_type + \" \" + msg.cfAuth.access_token,\n    \"Content-Type\": \"application/x-www-form-urlencoded\"\n};\nmsg.payload = {\n};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":490,"y":100,"wires":[["cbbe7dbd.d220b"]]},{"id":"cbbe7dbd.d220b","type":"http request","z":"c65f47d8.d266c8","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","x":550,"y":120,"wires":[["96c333b7.611c","1b9045c7.a55eda"]]},{"id":"6bd77466.0457ec","type":"change","z":"c65f47d8.d266c8","name":"ドロップダウン用配列作成","rules":[],"action":"","property":"","from":"","to":"","reg":false,"x":340,"y":60,"wires":[["5585377a.3f5428"]]},{"id":"96c333b7.611c","type":"function","z":"c65f47d8.d266c8","name":"ドロップダウン用配列作成","func":"var ret = [];\nret.push({\"未選択\" : \"\"});\nmsg.payload.resources.forEach(x =>\n{\n    var itm = [];\n    itm[x.entity.name] = x.metadata.guid;\n    ret.push(itm);\n});\n\nmsg.options = ret;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":720,"y":200,"wires":[["db4de15e.2b735","99e68255.48a4a"]]},{"id":"db4de15e.2b735","type":"ui_dropdown","z":"c65f47d8.d266c8","name":"","label":"","tooltip":"","place":"Select option","group":"93b2d5f.6f8ef28","order":1,"width":0,"height":0,"passthru":false,"multiple":false,"options":[{"label":"","value":"","type":"str"}],"payload":"","topic":"","x":840,"y":240,"wires":[["f3b2585e.03e558","80995ae.8df5fa8"]]},{"id":"f3b2585e.03e558","type":"ui_text","z":"c65f47d8.d266c8","group":"93b2d5f.6f8ef28","order":6,"width":0,"height":0,"name":"","label":"ステータス:","format":"{{msg.payload}}","layout":"row-left","x":810,"y":340,"wires":[]},{"id":"99500971.c5b698","type":"function","z":"c65f47d8.d266c8","name":"App 詳細 取得","func":"msg.url = \"https://api.ng.bluemix.net/\";\nmsg.url += \"/v2/apps/\" + msg.guid + \"/stats\" ;\nmsg.method = \"GET\";\nmsg.headers = {\n    'Authorization': msg.cfAuth.token_type + \" \" + msg.cfAuth.access_token,\n    \"Content-Type\": \"application/x-www-form-urlencoded\"\n};\nmsg.payload = {\n};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":460,"y":480,"wires":[["b6be316f.384dd"]]},{"id":"b6be316f.384dd","type":"http request","z":"c65f47d8.d266c8","name":"","method":"use","ret":"obj","url":"","tls":"","x":470,"y":520,"wires":[["d3e80650.909118","8a2d3a64.697d28"]]},{"id":"c43f0e98.7240d","type":"change","z":"c65f47d8.d266c8","name":"","rules":[{"t":"set","p":"guid","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":250,"y":440,"wires":[["9330daff.2c04f8"]]},{"id":"5585377a.3f5428","type":"subflow:ea4953fa.d6725","z":"c65f47d8.d266c8","name":"","x":350,"y":100,"wires":[["7a1374ba.156aec"]]},{"id":"9330daff.2c04f8","type":"subflow:ea4953fa.d6725","z":"c65f47d8.d266c8","name":"","x":290,"y":480,"wires":[["99500971.c5b698"]]},{"id":"34f77e2b.be6062","type":"change","z":"c65f47d8.d266c8","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"$round(payload.stats.usage.mem / 1000000, 2)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":560,"wires":[["60cd6bcd.1a0004"]]},{"id":"c1532a21.e8d8f8","type":"ui_gauge","z":"c65f47d8.d266c8","name":"","group":"93b2d5f.6f8ef28","order":2,"width":6,"height":4,"gtype":"gage","title":"CPU","label":"units","format":"{{value}}%","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":890,"y":680,"wires":[]},{"id":"f231cc0f.3993f","type":"ui_gauge","z":"c65f47d8.d266c8","name":"","group":"93b2d5f.6f8ef28","order":4,"width":6,"height":4,"gtype":"gage","title":"Disk","label":"units","format":"{{value}}","min":0,"max":"512","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":890,"y":620,"wires":[]},{"id":"60cd6bcd.1a0004","type":"ui_gauge","z":"c65f47d8.d266c8","name":"","group":"93b2d5f.6f8ef28","order":3,"width":6,"height":4,"gtype":"gage","title":"Memory","label":"units","format":"{{value}}","min":0,"max":"256","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":900,"y":560,"wires":[]},{"id":"baf4c521.f58528","type":"change","z":"c65f47d8.d266c8","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"$round(payload.stats.usage.disk / 1000000, 2)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":620,"wires":[["f231cc0f.3993f"]]},{"id":"3f296c82.a7eff4","type":"change","z":"c65f47d8.d266c8","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"$round(payload.stats.usage.cpu * 100, 3)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":700,"y":680,"wires":[["c1532a21.e8d8f8","8a2d3a64.697d28"]]},{"id":"8a2d3a64.697d28","type":"debug","z":"c65f47d8.d266c8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":910,"y":740,"wires":[]},{"id":"c68af762.6f8ed8","type":"change","z":"c65f47d8.d266c8","name":"アプリ一覧取得中メッセージ","rules":[{"t":"set","p":"payload","pt":"msg","to":"ちょっと待ってね","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":520,"y":340,"wires":[["f3b2585e.03e558"]]},{"id":"99e68255.48a4a","type":"change","z":"c65f47d8.d266c8","name":"アプリ一覧完了メッセージ","rules":[{"t":"set","p":"payload","pt":"msg","to":"準備できました","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":520,"y":280,"wires":[["f3b2585e.03e558"]]},{"id":"d3e80650.909118","type":"function","z":"c65f47d8.d266c8","name":"JSONata 使いたくて…","func":"msg.payload = msg.payload[\"0\"];\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":410,"y":620,"wires":[["34f77e2b.be6062","baf4c521.f58528","3f296c82.a7eff4"]]},{"id":"80995ae.8df5fa8","type":"link out","z":"c65f47d8.d266c8","name":"","links":["17c013ea.a5cd4c"],"x":995,"y":240,"wires":[]},{"id":"17c013ea.a5cd4c","type":"link in","z":"c65f47d8.d266c8","name":"","links":["80995ae.8df5fa8"],"x":115,"y":440,"wires":[["c43f0e98.7240d"]]},{"id":"6403508a.b390a","type":"comment","z":"c65f47d8.d266c8","name":"ドロップダウン選択後","info":"","x":150,"y":400,"wires":[]},{"id":"1b9045c7.a55eda","type":"debug","z":"c65f47d8.d266c8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1020,"y":200,"wires":[]},{"id":"93b2d5f.6f8ef28","type":"ui_group","z":"","name":"dashboard","tab":"bceebcc7.c1085","order":2,"disp":true,"width":18,"collapse":false},{"id":"bceebcc7.c1085","type":"ui_tab","name":"Tab 3","icon":"dashboard","order":3}]

認可フロー

[{"id":"ea4953fa.d6725","type":"subflow","name":"CF認可","info":"","category":"","in":[{"x":50,"y":30,"wires":[{"id":"3827a45a.128e3c"}]}],"out":[{"x":700,"y":240,"wires":[{"id":"8f9021c2.dcc","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"42036e2f.e65ce","type":"function","z":"ea4953fa.d6725","name":"トークン取得","func":"msg.url = msg.payload.authorization_endpoint ;\nmsg.url += \"/oauth/token\";\nmsg.method = \"POST\";\n//(補足) Y2Y6は、username:cf (passwordなし)をBase64でエンコードしたものになります。\nmsg.headers = {\n    'Authorization': \"Basic Y2Y6\",\n    \"Content-Type\": \"application/x-www-form-urlencoded\"\n};\nmsg.payload = {\n    'grant_type': \"password\",\n//    'client_id' : \"cf\",\n    'username'  : IBM Cloud ユーザ名,\n    'password': IBM Cloud パスワード,\n    'response_type' : 'token'\n};\nreturn msg;","outputs":1,"noerr":14,"initialize":"","finalize":"","x":420,"y":120,"wires":[["56819ad7.db63c4"]]},{"id":"56819ad7.db63c4","type":"http request","z":"ea4953fa.d6725","name":"認可エンドポイントに要求","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","x":500,"y":160,"wires":[["8f9021c2.dcc"]]},{"id":"3827a45a.128e3c","type":"http request","z":"ea4953fa.d6725","name":"認可エンドポイント取得","method":"GET","ret":"obj","paytoqs":"ignore","url":"https://api.ng.bluemix.net/v2/info","tls":"","persist":false,"proxy":"","authType":"","x":190,"y":80,"wires":[["42036e2f.e65ce"]]},{"id":"8f9021c2.dcc","type":"change","z":"ea4953fa.d6725","name":"認可情報確保","rules":[{"t":"set","p":"cfAuth","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":220,"wires":[[]]},{"id":"194aa920.eaa857","type":"comment","z":"ea4953fa.d6725","name":"出力は msg.cfAuth","info":"","x":630,"y":280,"wires":[]}]

最後に

ちょっと不便だなと思ったことを解決するアイディアを、すぐに形にできる Node-RED 大好きです。すこし古い情報でアプリを作ってしまったので、新しいバージョンの Cloud Foundry APIを使って実装しなおしたいです。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
0