【GCP】Google Cloud Storage での更新をPubSubで知る

Google Cloud Platform の Cloud Storage にファイルがアップロードされたことを通知として受け取る方法を紹介します。一応、最低限の動作確認ができたのでメモっておきます。Google Cloud にも使用法のページ([Pub/Sub Notifications for Cloud Storage の使用法](https://cloud.google.com/storage/docs/reporting-changes?hl=ja))があるのですが、あまり丁寧でないので一応。

# 目的: Cloud Storage にファイルがアップロードされたのを知りたい

### Storage の変更を受け取るには？

まず、Storage に変更があったときに通知を受け取るには２つ方法があります。

- PubSub のmessage として受け取る
- 実装したCloud Function で受けとる

PubSubを使っていて、この枠組みを使うのがスマートな設計であると思ったのでこちらを利用しました。

参考：[Cloud Storage の Pub/Sub 通知](https://cloud.google.com/storage/docs/pubsub-notifications)

### 何を通知してくれるのか？

読めば書いてあるのですが、通知のトリガーとなるイベントは下記のとおりです。

|Event Type | 内容 |
| --- | --- |
|OBJECT_FINALIZE |バケットで新しいオブジェクト（または既存オブジェクトの新しい世代）が作成|
|OBJECT_METADATA_UPDATE | オブジェクトのメタデータを更新 |
|OBJECT_DELETE| オブジェクトを削除 |
|OBJECT_ARCHIVE|(バージョニングが有効になっている場合にのみ)|

### PubSubのメッセージとして受け取るには

Storage の bucket に notification としてtopic を割り当てるだけです。bucket への変更を通知するpublisher を用意してもらう、というイメージです。
これはコマンドで設定できます。

```
$ gsutil notification create -t TOPIC_ID -f json gs://BUCKET_ID
```

くわしくは[gsutil notificationの使い方](https://cloud.google.com/storage/docs/gsutil/commands/notification)を見ると「いろいろあるなー」ということが分かります。

PubSub でsubscribe していると、Storage に変更があったときメッセージが送られてきます。メッセージはDataとAttributesから構成されますが、どんな変更があったを知らせる"Event Type"に入っています。最初Dataだけを見ていて「分からねーじゃん」と思って焦りました。^^;

# 動作確認

## まずは簡単な動作確認

### 環境用意（省略可)

適当な環境がある人や後で実装をしない人には不要ですが、一応。コンソール(console.google.cloud.com)でプロジェクトを作成します。プロジェクト(```[PROJECT_ID]```とします)で、必要な権限を付与したサービスアカウントを作成します。

Linux端末から、認証を通した後、サービスアカウントのカギを環境変数に設定します。

```
$ gcloud auth login
$ export GOOGLE_APPLICATION_CREDENTIALS=service_account.key
$ gcloud config set project PROJECT_ID
```

プロジェクトでPubSub を使えるようにしておきます。

### notification を用意する

(1) コンソールでbucketを用意します。 ```gsutil mb gs://[BUCKET_NAME]/``` でもできるはずなのですが、こちらで作成してもコンソールに現れなかったので、ここではコンソールで作成したものを利用します。

(2) topic を用意します

```
$ gcloud pubsub topics create TOPIC_ID
Created topic [projects/project_id/topics/topic_id].
```
(3) topic にbucket での変更を知らせるように設定します。

```
$ gsutil notification create -t TOPIC_ID -f json gs://BUCKET_ID
Created notification config projects/_/buckets/bucket_name/notificationConfigs/2
```

(4) topic に subscription を用意します。

```
$ gcloud pubsub subscriptions create SUBSCRIPTION_ID --topic=TOPIC_ID
Created subscription [projects/project_id/subscriptions/subscription_id].
```

### Storage にファイルをアップロードしたときの反応

手抜きなので、コンソール(ブラウザ)からファイルをアップロードしてみました。しばらくたって（すぐには反応が無い）からpull してみます。

```
$ gcloud pubsub subscriptions pull --auto-ack SUBSCRIPTION_ID
```
とすると応答があります。

受け取ったメッセージのAttribute にはファイル名や変更内容(EventType)の情報が入っています。

```
bucketId=bucket_trigger01
eventTime=2020-08-22T13:43:31.929768Z
eventType=OBJECT_FINALIZE
notificationConfig=projects/_/buckets/bucket_id/notificationConfigs/2
objectGeneration=1598103811929971
objectId=test.txt
payloadFormat=JSON_API_V1
```

メッセージのdata の方は json ですが、

```
{ 
  "kind": "storage#object",
   "id": "bucket_trigger01/test.txt/12345678901234", 
"selfLink":"https://www.googleapis.com/storage/v1/b/bucket_id/o/test.txt",
  "name": "test.txt",
  "bucket": "bucket_trigger01", 
   "generation": "12345678901234",
   "metageneration": "1",
   "contentType": "text/plain",                                                                                                          
   "timeCreated": "2020-08-22T13:43:31.929Z",                                                                                            
   "updated": "2020-08-22T13:43:31.929Z",
   "storageClass": "STANDARD",                                                                                                           "timeStorageClassUpdated": "2020-08-22T13:43:31.929Z",                                                                               "size": "13",                                                                                                                         "md5Hash": "ABCDEFGHIJK",                                                   "mediaLink": "https://www.googleapis.com/download/storage/v1/b/bucket_id/o/test.txt ?generation=1598103811929971&alt=media",
   "crc32c": "ABCDEF==",
   "etag": "abcedghijk=" 
} 
```

のような形で返ってきました。ファイル名、バケット名だけでなく generation も取得できますね。どう使うのかな。

# まとめ

### できたことと今後の課題

Storage の変更をPubSubで知る方法を確認した。
動かすにあたっては、自分の過去のメモを見ました。

- [【GCP】Cloud Storage のbucket へのアクセス権](https://qiita.com/xtkd/items/9161fe5eb75762ea113e)
- [【GCP】Google Pub/Sub の送受信確認(gcloud コマンド & python3)](https://qiita.com/xtkd/items/61e16fd980e5ea87519b)

今後ですが、とりあえず思いつくTODOは

- とりあえずpython script で変更を追跡し続けるプログラムを書いてみる。
- 変更メッセージの仕様をもっと読み込む

かな。あ、日付が変わった。
(2020/08/22)

とりあえず使わなそうなので、このまま一時保留します。(2020/09/03)