[GCP]Cloud StorageトリガーでCloud Functionsを動かす

# はじめに
Cloud StorageトリガーでCloud Functionsを動かす方法をまとめています。
記載している内容は、基本的にGoogle Cloudが公開しているチュートリアルの内容に沿っています。

*注意事項*
*Google Cloudの日本語ドキュメントに記載されているサンプルプログラムは実行してもエラーとなるものが多いです。そのためサンプルプログラムを試す際にはLanguageをEnglishにして、そこで表示されるサンプルプログラムを利用してください。*

# Cloud Functionsで使用するトリガーとは
Cloud Functionsは以下4種類のいずれかから呼び出されることで実行できます。この呼び出し元のことをトリガーと言います。
参考：https://cloud.google.com/functions/docs/concepts/events-triggers?hl=ja#events

* HTTP
* Cloud Storage
* Cloud Pub/Sub
* Firebase（DB、Storage、アナリティクス、Auth）

今回はCloud Storageを起点としてCloud Functionsを呼び出しますので、Cloud Storageトリガーの詳細を確認します。Cloud Storageトリガーの詳細なトリガーには以下4種類があります。
参考：https://cloud.google.com/functions/docs/calling/storage?hl=ja

* google.storage.object.finalize（オブジェクト作成など）
* google.storage.object.delete（オブジェクトの削除）
* google.storage.object.archive（オブジェクトのアーカイブ）
* google.storage.object.metadataUpdate（オブジェクトのメタデータ更新）

今回はCloud Storageにファイルが保存されるたびにCloud Functionsを呼び出そうと思うので、google.storage.object.finalizeトリガーを利用することにします。

# google.storage.object.finalizeトリガーを使ってみる
以下の手順は、チュートリアルをベースに作成しています。
参考：https://cloud.google.com/functions/docs/tutorials/storage

繰り返しになりますが日本語ドキュメントだと動かないプログラムやコマンドが書かれていますので、英語ドキュメントで確認することを推奨いたします。

## 1. Cloud Functionsで実行する関数の作成
Cloud shellを起動し適当なフォルダを作成し、作成したフォルダ内に以下を保存します。
この関数はCloud Storageにアップロードされたファイルのファイル名などの情報をログに記録するものです。

```js:index.js
/**
 * Generic background Cloud Function to be triggered by Cloud Storage.
 *
 * @param {object} data The event payload.
 * @param {object} context The event metadata.
 */
exports.helloGCSGeneric = (data, context) => {
  const file = data;
  console.log(`  Event ${context.eventId}`);
  console.log(`  Event Type: ${context.eventType}`);
  console.log(`  Bucket: ${file.bucket}`);
  console.log(`  File: ${file.name}`);
  console.log(`  Metageneration: ${file.metageneration}`);
  console.log(`  Created: ${file.timeCreated}`);
  console.log(`  Updated: ${file.updated}`);
};
```

# 2. Cloud Storageのバケット作成
Cloud Functionsのトリガーとなるバケットを作成します。

# 3. デプロイ
以下のコマンドでデプロイします。
YOUR_TRIGGER_BUCKET_NAME には「2. Cloud Storageのバケット作成」で作成したバケット名を入力してください。

```sh
gcloud functions deploy helloGCSGeneric --runtime nodejs8 --trigger-resource YOUR_TRIGGER_BUCKET_NAME --trigger-event google.storage.object.finalize
```

# 4. Cloud Storageにファイルアップロード
「2. Cloud Storageのバケット作成」で作成したバケットに適当なファイルをアップロードしてください。

# 5. ログ確認
StackDriverから確認しても良いですが、Cloud shellから以下のコマンドを実行することで最新のログ20件を表示することができます。

```
gcloud beta functions logs read --limit 20
```

以下のようなログが記録されていれば成功です。
Metagenerationはメタデータの変更時に更新され、作成時は1になります。

```
Event 779317620839983
Event Type: google.storage.object.finalize
Bucket: test-bucket
File: upload/test.txt
Metageneration: 1
Created: 2019-11-05T06:10:09.175Z
Updated: 2019-11-05T06:10:09.175Z
```

なお日本語ドキュメントのプログラムをコピペして実行すると「textPayload: "TypeError: Cannot read property 'xxxxx' of undefined」のエラーがログに記録されました。（2019/11/5時点）

# 参考情報
## イベントパラメータ

https://cloud.google.com/functions/docs/writing/background?hl=ja#event_parameter

| プロパティ | 説明 | 型 |
|:--|:--|:--|
| data | イベントのデータ オブジェクト。 | オブジェクト |
| context | イベントのコンテキスト オブジェクト。 | オブジェクト |
| context.eventId | イベントの一意の ID。 | 文字列 |
| context.timestamp | このイベントが作成された日時。 | 文字列（ISO 8601） |
| context.eventType | イベントのタイプ。 | 文字列 |
| context.resource | イベントを発行したリソース。 | 文字列 |