LoginSignup
7
8

More than 5 years have passed since last update.

IBM Cloud Functions(OpenWhisk)を使いNode-RED Flow定義をバージョン管理する

Posted at

こんにちは、水津です。
この記事は、IBM Cloud Advent Calendar 2017 23日目の投稿です。

はじめに

Node-REDで開発する際に困るのが、フローのバージョン管理。特に複数人で開発していると、間違って更新し他人の更新を消しちゃうことも。今回はそんな悩みを解決するために、IBM Cloud上のFunctionsとNode-REDを活用し、Node-REDのフロー定義更新を自動的にGitに反映する、Node-RED Flowの簡易的なバージョン管理システムを作りたいと思います。

構成

今回はこんな構成での実装を行います。
スクリーンショット 2017-12-23 23.02.23.png

IBM GitLab の準備

まずは、Flow定義の保存先(バージョン管理先)となるGitLabのリポジトリを準備します。今回は、IBM Cloudが提供してますGitLab環境を用いたいと思います。

  • テキトウな名称で新規リポジトリを作成ください。
  • 作成後、リポジトリの「Project ID」をメモください。(あとで、API CALLの設定を行う際、使用します) スクリーンショット 2017-12-23 23.09.41.png
  • アカウントの「Personal Access Token」を作成し、トークンをメモください。(あとで、API CALLの設定を行う際、使用します) スクリーンショット 2017-12-23 23.17.47.png

これでGitLabの準備は完了です。

IBM Cloud Functions(OpenWhisk)の実装

続いて、Node-REDのFlow定義が保存されているCloudantの更新を検知し動かす、「Functions(機能)」の実装を行っていきたいと思います。

  • 「機能」の開始 > 概要より、「作成の開始」をクリックし、まずはシーケンスを作成します。 スクリーンショット 2017-12-23 23.22.15.png
  • 任意のシーケンス名を入力、「Use Public」の「Websocket」を選択し、必要パラメータを入力します。(「uri」は後ほど行うNode-RED実装のWebsocket uriと同じ値にします) スクリーンショット 2017-12-23 23.30.08.png
  • シーケンスのアクション一覧にて「Add」を押下し、もう一つアクションを追加します。 スクリーンショット 2017-12-23 23.36.30.png

アクションのコードは以下のように定義ください。

  function main(params) {
     var msg = {};
     msg.payload = params.id;
     return msg;
  }

その後、以下のような順番で保存ください。
スクリーンショット 2017-12-23 23.47.10.png

  • 続いて、作成したシーケンスにトリガーを追加します。追加するトリガーは、「Cloudant」を選択ください。 スクリーンショット 2017-12-23 23.51.50.png

登録し終わると、以下のようになります。
スクリーンショット 2017-12-23 23.54.11.png

これで、CloudantのUpdateを検知し、WebsocketでUpdateされたDocumentのIDをSendする、Functions(機能)の実装が完了しました。

Node-RED の実装

続いて、Functions(機能)から送られてきたDocumentのIDをもとに、Flow定義をGitにPushするNode-REDのフローを定義します。

  • まずは、Node-REDにGitLabに接続するためのNodeを追加します。パレットの管理より、ノードの追加で「gitlab」を検索し、node-red-contrib-gitlab ノードを追加ください。(私の自作ノードです)
    スクリーンショット 2017-12-24 0.01.55.png

  • その後、以下のようにフローを定義ください。
    スクリーンショット 2017-12-24 0.05.15.png

フロー定義は以下になります。


[
    {
        "id": "f457b9b7.dea6d",
        "type": "websocket in",
        "z": "4ab9fe27.86f9c8",
        "name": "",
        "server": "166ec69b.fef401",
        "client": "",
        "x": 110,
        "y": 100,
        "wires": [
            [
                "80dfb138.ecced",
                "1b444420.62923c"
            ]
        ]
    },
    {
        "id": "80dfb138.ecced",
        "type": "debug",
        "z": "4ab9fe27.86f9c8",
        "name": "",
        "active": true,
        "console": "false",
        "complete": "true",
        "x": 270,
        "y": 100,
        "wires": []
    },
    {
        "id": "b03e8025.2dc4f8",
        "type": "debug",
        "z": "4ab9fe27.86f9c8",
        "name": "",
        "active": true,
        "console": "false",
        "complete": "false",
        "x": 650,
        "y": 400,
        "wires": []
    },
    {
        "id": "6972a335.8a49f4",
        "type": "GitLab-Update-RepositoryFile",
        "z": "4ab9fe27.86f9c8",
        "name": "",
        "branch_name": "master",
        "encoding": "text",
        "gitlabconfig": "fa916f31.d3a12",
        "x": 430,
        "y": 400,
        "wires": [
            [
                "b03e8025.2dc4f8"
            ]
        ]
    },
    {
        "id": "d8082f39.a124",
        "type": "debug",
        "z": "4ab9fe27.86f9c8",
        "name": "",
        "active": true,
        "console": "false",
        "complete": "payload",
        "x": 1030,
        "y": 540,
        "wires": []
    },
    {
        "id": "87c6cbda.c168c",
        "type": "catch",
        "z": "4ab9fe27.86f9c8",
        "name": "",
        "scope": [
            "6972a335.8a49f4"
        ],
        "x": 360,
        "y": 440,
        "wires": [
            [
                "4d03b085.c2dcc",
                "f4070782.4803a8"
            ]
        ]
    },
    {
        "id": "4d03b085.c2dcc",
        "type": "switch",
        "z": "4ab9fe27.86f9c8",
        "name": "",
        "property": "_error.statusCode",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "400",
                "vt": "num"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "true",
        "outputs": 2,
        "x": 390,
        "y": 560,
        "wires": [
            [
                "5055bcc.3113cc4"
            ],
            [
                "9780af03.3d19f"
            ]
        ]
    },
    {
        "id": "9780af03.3d19f",
        "type": "debug",
        "z": "4ab9fe27.86f9c8",
        "name": "",
        "active": true,
        "console": "false",
        "complete": "true",
        "x": 530,
        "y": 580,
        "wires": []
    },
    {
        "id": "7dde70e9.f74138",
        "type": "GitLab-Create-RepositoryFile",
        "z": "4ab9fe27.86f9c8",
        "name": "",
        "branch_name": "master",
        "encoding": "text",
        "gitlabconfig": "fa916f31.d3a12",
        "x": 820,
        "y": 540,
        "wires": [
            [
                "d8082f39.a124"
            ]
        ]
    },
    {
        "id": "bee7ea4.93eca18",
        "type": "comment",
        "z": "4ab9fe27.86f9c8",
        "name": "IBM Cloud Functions からMSG受信",
        "info": "",
        "x": 180,
        "y": 60,
        "wires": []
    },
    {
        "id": "9c5b58f8.0a78d",
        "type": "cloudant in",
        "z": "4ab9fe27.86f9c8",
        "name": "Flow定義を取得",
        "cloudant": "",
        "database": "nodered",
        "service": "KS-Test-20171211-cloudantNoSQLDB",
        "search": "_id_",
        "design": "",
        "index": "",
        "x": 440,
        "y": 140,
        "wires": [
            [
                "26d24ca.e909734"
            ]
        ]
    },
    {
        "id": "947eff54.91dc6",
        "type": "function",
        "z": "4ab9fe27.86f9c8",
        "name": "Git PUSH MSG作成",
        "func": "var payloadMessage = {\n    \"file_path\": msg.process._id + \".json\",\n    \"content\": msg.payload,\n    \"commit_message\": \"Update Node-RED Flow\"\n};\n\nmsg.payload = payloadMessage;\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 480,
        "y": 260,
        "wires": [
            [
                "7707921c.c4755c",
                "6972a335.8a49f4"
            ]
        ]
    },
    {
        "id": "1b444420.62923c",
        "type": "function",
        "z": "4ab9fe27.86f9c8",
        "name": "IDを退避",
        "func": "msg.process =  {\n    \"_id\" : msg.payload\n};\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 280,
        "y": 140,
        "wires": [
            [
                "9c5b58f8.0a78d"
            ]
        ]
    },
    {
        "id": "7707921c.c4755c",
        "type": "debug",
        "z": "4ab9fe27.86f9c8",
        "name": "",
        "active": true,
        "console": "false",
        "complete": "true",
        "x": 690,
        "y": 260,
        "wires": []
    },
    {
        "id": "26d24ca.e909734",
        "type": "json",
        "z": "4ab9fe27.86f9c8",
        "name": "",
        "pretty": true,
        "x": 290,
        "y": 260,
        "wires": [
            [
                "efda5601.e13fe8",
                "947eff54.91dc6"
            ]
        ]
    },
    {
        "id": "34bb144a.7dbd0c",
        "type": "comment",
        "z": "4ab9fe27.86f9c8",
        "name": "Flow定義をbase64変換",
        "info": "",
        "x": 340,
        "y": 300,
        "wires": []
    },
    {
        "id": "ce0f378e.d9db9",
        "type": "comment",
        "z": "4ab9fe27.86f9c8",
        "name": "ファイル更新",
        "info": "",
        "x": 490,
        "y": 360,
        "wires": []
    },
    {
        "id": "3d9fa74c.87c2f8",
        "type": "comment",
        "z": "4ab9fe27.86f9c8",
        "name": "ファイル新規登録",
        "info": "",
        "x": 790,
        "y": 500,
        "wires": []
    },
    {
        "id": "dfe5779d.fb3b28",
        "type": "comment",
        "z": "4ab9fe27.86f9c8",
        "name": "まだファイルがなく失敗した場合",
        "info": "",
        "x": 250,
        "y": 480,
        "wires": []
    },
    {
        "id": "efda5601.e13fe8",
        "type": "debug",
        "z": "4ab9fe27.86f9c8",
        "name": "",
        "active": true,
        "console": "false",
        "complete": "false",
        "x": 450,
        "y": 220,
        "wires": []
    },
    {
        "id": "f4070782.4803a8",
        "type": "debug",
        "z": "4ab9fe27.86f9c8",
        "name": "",
        "active": true,
        "console": "false",
        "complete": "true",
        "x": 510,
        "y": 440,
        "wires": []
    },
    {
        "id": "5055bcc.3113cc4",
        "type": "function",
        "z": "4ab9fe27.86f9c8",
        "name": "Git PUSH MSG作成",
        "func": "msg.payload = msg.inputMessage.payload;\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 580,
        "y": 540,
        "wires": [
            [
                "7dde70e9.f74138"
            ]
        ]
    },
    {
        "id": "166ec69b.fef401",
        "type": "websocket-listener",
        "z": "",
        "path": "/ws/push",
        "wholemsg": "false"
    },
    {
        "id": "fa916f31.d3a12",
        "type": "gitlab-config",
        "z": "",
        "url": "https://git.ng.bluemix.net/api/v3",
        "project_id": "11111",
        "name": "TEST"
    }
]

これで実装は完了です。

使ってみる

試しに動かしてみます。今回は(別の環境作ってないので)今回作成したNode-REDのフローの変更を検知しGitにPushさせる形で試します。

  • Node-RED上で「デプロイ」ボタンを押します。そうすると、まずはFanctionsが走ります。Functionsでは以下のようなログが確認できます。 スクリーンショット 2017-12-24 0.52.41.png

その後、Node-RED側に処理がわたり、Gitに(初回は)新規ファイルが追加されます。
スクリーンショット 2017-12-24 0.38.14.png

  • 試しに更新してみます。フローを少し変更し、「デプロイ」を押します。そうするとファイルの更新が行われ、Git上ではdiffも確認することができます。 スクリーンショット 2017-12-24 0.42.11.png

まとめ

いかがでしたでしょうか。これでFlow更新時のバージョン管理が自動的に行われるようになりますので、Node-REDで複数人でフロー開発する際も安心して進められるのでは、と思います!

7
8
0

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
  3. You can use dark theme
What you can do with signing up
7
8