ICOSへの変更をトリガーにIBM Cloud Functionsを呼び出す

#1. はじめに
IBM CloudにはICOS(IBM Cloud Object Storage)というオブジェクトストレージがあります。例えば、「ICOSにzipファイルをアップロードしたら、通知する、ファイル展開する、キャッシュをクリアする」など、ICOS上に発生したイベントをもとに何か処理を行いたくはないでしょうか？この記事では、ICOSのイベントをもとにIBM Cloud Functions(Serverless)を呼び出すための方法について記載しています。

- 公式ドキュメントとしては以下に記載があります（ブラウザの言語設定を英語にしてアクセスしてください。言語が日本語だとアクセスできません）。<br>(Experimental) Object Storage events source<br>
https://cloud.ibm.com/docs/openwhisk?topic=cloud-functions-cloud_object_storage#cloud_object_storage
- ~~現在は正式にGAされておらず、`us-south`でのみ試験的な利用が可能です~~。 2019/11/11現在、東京リージョンでも利用可能になりました。 https://cloud.ibm.com/docs/services/cloud-object-storage/basics?topic=cloud-object-storage-service-availability&locale=en-us

#2. 設定
##2.1 事前準備
ibmcloudコマンドおよびpluginを導入・最新化し、ログインします。

```
# ibmcloud update

# ibmcloud plugin install cloud-functions

# ibmcloud plugin list
インストール済みプラグインをリストしています...

プラグイン名                       バージョン   状況
cloud-functions/wsk/functions/fn   1.0.30

# ibmcloud login
```

（参考）
検証時には、`ibmcloud login -sso`でログインするとAPI endpointとして`https://cloud.ibm.com`が使われていたが、これだとうまく動かない時があり、昔のAPI endpointである`https://api.ng.bluemix.net`の方を利用する必要があった。。今は修正されているはず。
https://stackoverflow.com/questions/54610580/wrong-resource-controller-url-when-binding-a-service-to-a-cloud-function

##2.2 us-southリージョンおよび自分のリソースグループにスイッチ
IBM Cloud functionsのICOS Eventは現時点で`us-south`のみのため、`us-south`にスイッチします。今回はICOSのResource groupを`yasuda`で作っているので、以下のように実行します。

```
# ibmcloud target -r us-south -g yasuda --cf
```

##2.3 ICOSイベント用パッケージの確認

利用可能なパッケージを検索し、`/whisk.system/cos-experimental `があることを確認します。

```
# ibmcloud fn package list /whisk.system
packages
/whisk.system/weather                                                  shared
/whisk.system/websocket                                                shared
/whisk.system/samples                                                  shared
/whisk.system/utils                                                    shared
/whisk.system/slack                                                    shared
/whisk.system/cloudant                                                 shared
/whisk.system/cos-experimental                                         shared
/whisk.system/alarms                                                   shared
/whisk.system/messaging                                                shared
/whisk.system/pushnotifications                                        shared
/whisk.system/watson-textToSpeech                                      shared
/whisk.system/github                                                   shared
/whisk.system/combinators                                              shared
/whisk.system/watson-speechToText                                      shared
/whisk.system/watson-translator                                        shared
```

`cos-experimental`の詳細を見てみます。以下より、changesというEntity名のfeedが含まれていることがわかります。また呼び出し時のパラメーターも確認できます。

```
# ibmcloud fn package get --summary /whisk.system/cos-experimental
package /whisk.system/cos-experimental: COS Provider service
   (parameters: *apihost)
 feed   /whisk.system/cos-experimental/changes: Event provider COS feed
   (parameters: apikey, auth_endpoint, bucket, endpoint, interval)

# ibmcloud fn action get --summary /whisk.system/cos-experimental/changes
action /whisk.system/cos-experimental/changes: Event provider COS feed
   (parameters: *apihost, apikey, auth_endpoint, bucket, endpoint, interval)
```

##2.4 ICOSイベント用のパッケージ・バインディングを作成する

`cos-experimental`パッケージは雛形です。この雛形であるパッケージを元に、`myCosPkg`というインスタンス化されたユーザー固有のパッケージ・バインディングを作成します。

```
# ibmcloud fn package bind /whisk.system/cos-experimental myCosPkg
ok: created binding myCosPkg

# ibmcloud fn package list
packages
/IBMCLOUDJPN_dev/myCosPkg                                              private

# ibmcloud fn package get myCosPkg
package /IBMCLOUDJPN_dev/myCosPkg: Returns a result based on parameter apihost
   (parameters: *apihost)
 feed   /IBMCLOUDJPN_dev/myCosPkg/changes: Event provider COS feed
   (parameters: apikey, auth_endpoint, bucket, endpoint, interval)
```

##2.5 ICOSへの接続情報(credential)をバインドする

```
# ibmcloud fn service bind cloud-object-storage myCosPkg
Credentials 'credential1' from 'cloud-object-storage' service instance 'Cloud Object Storage-SYASUDA' bound to 'myCosPkg'.

# ibmcloud fn package get myCosPkg
（略。apikeyなどのcredential情報が登録されていることが分かる）

```

##2.6 triggerを作成する
今回は、trigger名として`myCosTrigger`を、ICOSのbucket名として`mybucket103`を使っています。
また、us-southにあるため、bucketのendpoint情報として`s3.us-south.cloud-object-storage.appdomain.cloud`を使っています。

```
# ibmcloud fn trigger create myCosTrigger --feed myCosPkg/changes -p bucket mybucket103 -p endpoint s3.us-south.cloud-object-storage.appdomain.cloud
（略）

# ibmcloud fn trigger get myCosTrigger
（構成の確認）
```

##2.7 actionを作成する

ICOSに変更があった際に呼び出す処理（`action`)を作成します。ここでは、とりあえず適当な文を返し、どういうパラメーターが引き渡されるのかを確認するだけの`action`を作りました。

```node.js:myCosChangeAction.js
function main(params) {
    console.log("This is a test action of ICOS Trigger.");
    console.log(new Date);
    if (Object.keys(params).length == 0) {
        return {"message": "null"};
    } else {
        console.log("bucket: "     + params.bucket);
        console.log("endpoint: "   + params.endpoint);
        console.log("objectName: " + params.file.Key);
        console.log("objectSize: " + params.file.Size);
        return {"message": "success"};
    }
}

```
```
# ibmcloud fn action create myCosChangeAction myCosChangeAction.js --kind nodejs:10
ok: created action myCosChangeAction

# ibmcloud fn action list
actions
/IBMCLOUDJPN_dev/myCosChangeAction                                     private nodejs:10
```

##2.8 ruleを作成する
`rule`は、`trigger`が発動した際にどの`action`を実行するかを定義するためのものです。

```
# ibmcloud fn rule create myCosRule myCosTrigger myCosChangeAction
ok: created rule myCosRule
# ibmcloud fn rule get myCosRule
ok: got rule myCosRule
{
    "namespace": "IBMCLOUDJPN_dev",
    "name": "myCosRule",
    "version": "0.0.1",
    "status": "active",
    "trigger": {
        "name": "myCosTrigger",
        "path": "IBMCLOUDJPN_dev"
    },
    "action": {
        "name": "myCosChangeAction",
        "path": "IBMCLOUDJPN_dev"
    },
    "publish": false
}
```

#3. 設定結果の確認
ICOSにオブジェクトをアップロードします。このtriggerはオブジェクトの追加時だけでなく、編集時や削除時にも発動するようです。その前に以下を実行しておくと、アップロードによるActivationを監視することが可能です。

```
# ibmcloud fn activation poll
```

1分ほど待つとtriggerが発動したことを確認できます。1分というのがbucket polling intervalのデフォルトのようです。もし`-p interval MIN`を指定すれば、この間隔を広げることができます。（MINの値は1分以上である必要があります）

```
# ibmcloud fn activation poll
Enter Ctrl-c to exit.
Polling for activation logs

Activation: 'myCosChangeAction' (c14301b618b746c18301b618b736c1c0)
[
    "2019-04-11T05:11:53.625828296Z stdout: This is a test action of ICOS Trigger.",
    "2019-04-11T05:11:53.627447991Z stdout: 2019-04-11T05:11:53.625Z",
    "2019-04-11T05:11:53.627582941Z stdout: bucket: mybucket103",
    "2019-04-11T05:11:53.627706973Z stdout: endpoint: s3.us-south.cloud-object-storage.appdomain.cloud",
    "2019-04-11T05:11:53.627785731Z stdout: objectName: index.html",
    "2019-04-11T05:11:53.627886394Z stdout: objectSize: 339"
]

Activation: 'myCosTrigger' (72010156f0184809810156f018a80961)
[
    "{\"statusCode\":0,\"success\":true,\"activationId\":\"c14301b618b746c18301b618b736c1c0\",\"rule\":\"IBMCLOUDJPN_dev/myCosRule\",\"action\":\"IBMCLOUDJPN_dev/myCosChangeAction\"}"
]
```

activationの記録は直近14日ほどが残り、それ以上経過したものは自動的に削除されるようです。

```txt:イベントactivationのリスト
# ibmcloud fn activation list
activations
c14301b618b746c18301b618b736c1c0 myCosChangeAction
72010156f0184809810156f018a80961 myCosTrigger
（以下省略）

```

以下のように、`myCosTrigger`のログと結果が分かります。このreturnの内容が、`myCosChangeAction`の引数(params)に渡されるようです。

```txt:myCosTriggerの履歴
# ibmcloud fn activation logs 72010156f0184809810156f018a80961
{"statusCode":0,"success":true,"activationId":"c14301b618b746c18301b618b736c1c0","rule":"IBMCLOUDJPN_dev/myCosRule","action":"IBMCLOUDJPN_dev/myCosChangeAction"}

# ibmcloud fn activation result 72010156f0184809810156f018a80961
{
    "bucket": "mybucket103",
    "endpoint": "s3.us-south.cloud-object-storage.appdomain.cloud",
    "file": {
        "ETag": "\"8a32f8d4a73265cab8b68a8ae19997be\"",
        "Key": "index.html",
        "LastModified": "2019-04-11T05:11:47.327Z",
        "Owner": {
            "DisplayName": "2c66d594-86d5-4a50-ba34-cedb18fe3126",
            "ID": "2c66d594-86d5-4a50-ba34-cedb18fe3126"
        },
        "Size": 339,
        "StorageClass": "STANDARD"
    },
    "key": "index.html",
    "status": "added"
}
```

以下のように、myCosChangeActionで実装していた`console.log()`の結果などが出力されていることが分かります。

```txt:myCosChangeActionの履歴
# ibmcloud fn activation logs c14301b618b746c18301b618b736c1c0
2019-04-11T05:11:53.625828296Z stdout: This is a test action of ICOS Trigger.
2019-04-11T05:11:53.627447991Z stdout: 2019-04-11T05:11:53.625Z
2019-04-11T05:11:53.627582941Z stdout: bucket: mybucket103
2019-04-11T05:11:53.627706973Z stdout: endpoint: s3.us-south.cloud-object-storage.appdomain.cloud
2019-04-11T05:11:53.627785731Z stdout: objectName: index.html
2019-04-11T05:11:53.627886394Z stdout: objectSize: 339

# ibmcloud fn activation result c14301b618b746c18301b618b736c1c0
{
    "message": "success"
}

```