mockmockでSORACOM Funnelにデータを送るプロジェクトを作成する

この記事は、[mockmockアドベントカレンダー](https://qiita.com/advent-calendar/2019/mockmock)8日目の記事です。

昨日は @cheekykorkind による「[mockmockでSORACOM Beamにデータを送るプロジェクトを作成する](https://qiita.com/cheekykorkind/items/b62d6392be53ac3baf39)」でした。

今回はmockmockからSORACOM Funnel経由でGCPへデータを送ってみます。
ちなみに[mockmockの公式のガイド](https://console.mock-mock.com/docs/guides/soracom)ではAWS IoTへ送信しています。興味がある方はそちらもご参照ください。

##  SORACOM Funnelとは？

以下、[公式Docs](https://dev.soracom.io/jp/funnel/what-is-funnel/)から説明を抜粋します。

デバイスからのデータを特定のクラウドサービスに直接転送するアダプターです。

![soracom_funnel.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120225/caf251fc-0d34-2eb9-1678-2095be82d4eb.png)

### メリット

- デバイスにクラウドサービスのSDK等をインストールしなくとも、Funnelを利用すればHTTPやTCPなどを使用してデータを送信できる。
- 接続先・認証情報をデバイスに保持する必要がない。（SORACOM内に配置する）
- 主要なクラウドベンダーのサービスに対応している。

### [SORACOM Beam](https://dev.soracom.io/jp/beam/what-is-beam/)との違い

- Beamは、任意のエンドポイントにデータへ転送可能。
- Funnelは、サポートする特定のクラウドサービスへの転送のみ可能。
  - 本来デバイス上で必要なSDK使った実装や認証をFunnelが肩代わりするため、デバイス側はシンプルな実装で済む。

## mockmockからSORACOM Funnelを使えると何がうれしいの？

（Beamの場合と同じですが）多量のSORACOM SIMを持つデバイスからFunnelへの送信テストが簡単にできます。
実デバイスを用意する前にテストできるので、
「実デバイスの用意ができたから負荷テストしたらさばけなかった。インフラの見直さなきゃ…、スケジュールやばい…。」
みたいな状況を回避するのに役立つと思っています。

## 具体的な手順

### GCPでの作業

Cloud Pub/Subのトピック・サブスクリプションを作成します。

#### GCPコンソール上でプロジェクト作成 & 認証情報をダウンロード

ここはSORACOM公式の[[SORACOM FunnelのCloud Pub/Subアダプターを使用してGoogle Cloud Platformにデータを送信する]](https://dev.soracom.io/jp/start/funnel_pubsub/)の手順そのままなので、さらっとまとめます。

1. GCPコンソールにログインし、新規プロジェクト作成
2. サイドメニューの `API とサービス` をクリックし、`+ APIとサービスを有効化` ボタンをクリック
3. `Cloud Pub/Sub API` を検索してクリックし、 `Cloud Pub/Sub API` を有効化する
4. `Cloud Pub/Sub API` の認証情報をクリックし、 `+ 認証情報を作成` > `サービス アカウント` をクリック
5. サービスアカウント名・IDは適当に入力し、役割を`Pub/Sub管理者`にしてサービスアカウントを作成する
6. キーを作成し、JSONファイルをダウンロードする



#### トピックとサブスクリプションの作成

Terraformを使ってやってみます。
※Terraformのインストール方法は割愛させていただきます。

適当な作業ディレクトリ内に以下の`main.tf`と`variable.tf`を置きます。`variable.tf`のプロジェクト名と認証情報パスは自身のものに書き換える必要があります。

```main.tf

provider "google" {
  credentials = "${file("${var.credential.data}")}"
  project     = "${var.project_name}"
  region      = "asia-northeast1"
}

resource "google_pubsub_topic" "my-topic" {
  name    = "my-topic"
  project = "${var.project_name}"
}

resource "google_pubsub_subscription" "example" {
  name    = "my-sub"
  project = "${var.project_name}"
  topic   = google_pubsub_topic.my-topic.name

  message_retention_duration = "600s" # 未確認メッセージの保持期間
  retain_acked_messages      = false  # 確認済みメッセージを保持するかどうか
  ack_deadline_seconds       = 20     # この時間以内に確認応答がないと再送信される

  expiration_policy {
    ttl = "300000.5s" # サブスクリプションの有効期限条件
  }
}
```

```variable.tf
variable "project_name" {
  default = "<your-project-name>"
}

variable "credential" {
  default = {
    data = "<your-credential-path>"
  }
}
```

以下のコマンドを実行します。

```shell

terraform init
terraform plan
terraform apply
```

これで完了です。なお、私の環境のTerraformのバージョン情報は下記となります。

```
Terraform v0.12.10
+ provider.google v3.1
```

### mockmockでの作業

手順は[mockmockの公式のガイド](https://console.mock-mock.com/docs/guides/soracom)と同様です。（[ここ](https://console.mock-mock.com/docs/guides/soracom#create_project)から[ここ](https://console.mock-mock.com/docs/guides/soracom#create_credential)までと同様）また、 前日の記事とも同様となります。そのため、途中まではさらっと説明させていただきます。

1. 新規プロジェクト作成
2. グラフバリュージェネレーターを作成
3. データテンプレートを作成
4. mockグループを作成
5. mockステータスを作成
6. mockを作成
7. SORACOM 認証キーを作成する
8. soracom cliのprofileを設定する
9. SORACOM 認証情報を作成する

最後の作業は、Funnel向けの作業なので説明させてください。
Funnelで接続するクラウドサービスの認証情報をSORACOMに登録する必要があります。
その手順ですが、「mockmockで空の認証情報を払い出させて、その後自身の認証情報で上書きする」という少しトリッキーなものです。

まず、ここでは空の認証情報払い出させたます。
[プロジェクト設定]>[SORACOM 認証情報ストア]>[新規作成]をクリックします。 すると、SORACOM 認証情報ストアにSORACOM 認証情報が追加されます。

<img width="762" alt="create_credential.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120225/367f455d-e985-69ff-13c8-65d7919024df.png">


### SORACOMでの作業

続いてSORACOMでの作業になります。通常のSORACOMでの作業と異なり、[SORACOM User Console](https://console.soracom.io/#/login?coverage_type=jp)で作業することができないので、少しわかりにくいかもしれません。（mockmockが所持するSORACOMアカウントを利用するため、お持ちのコンソールでの操作はできない。）

#### 1. 手持ちの認証情報を登録する

まず、上述した手順にてダウンロードしたPub/Subの認証情報JSONをJSON文字列にします。

```shell
cat <ダウンロードした認証情報JSON> | jq -Rs .
```

次に、以下のようなJSONファイルを作成します。`type`を`google-service-account-json`とし、`credentials.credentials`に上記のJSON文字列を貼り付けます。

```credential.json
{
  "type": "google-service-account-json",
  "description": "for_mockmock",
  "credentials": {
    "credentials": "<JSON文字列>"
  }
}
```

続いて以下のようにコマンドを実行します。 SORACOM 認証情報IDは上述した手順にて作成したものを使用します。

```
soracom credentials update --credentials-id ${SORACOM 認証情報ID} --body @credential.json --profile mockmock
```

#### 2. デバイスグループの設定を変更する

以下のようなJSONファイルを作成します。

```funnel.json
[
  {
    "key": "contentType",
    "value": "json"
  },
  {
    "key": "credentialsId",
    "value": "${SORACOM 認証情報ID}"
  },
  {
    "key": "destination",
    "value": {
      "provider": "google",
      "resourceUrl": "<作成したPub/Subのトピック名>",
      "service": "pubsub"
    }
  },
  {
    "key": "enabled",
    "value": true
  }
]
```

続いて以下のようにコマンドを実行します。SORACOM デバイスグループIDはmockmockのプロジェクト設定画面に表示されているものを使用します。

```shell
soracom groups put-config --group-id ${SORACOM デバイスグループID} --namespace SoracomFunnel --body @funnel.json --profile mockmock
```

これで設定は完了です。

### 実際にデータを送ってみる

`テスト送信機能`を使って、実際にデータを送ってみます。[mockステータス]タブからmockステータス画面に戻り、 [テスト送信]メニューの[送信]ボタンをクリックします。

![test_send_result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/120225/32317720-7596-6552-905f-08f0cc628656.png)

レスポンスコードが`204`となっているので、ちゃんと送信できてそうです。（`204: No Content`は、リクエストが成功した事を示すが、クライアントは現在のページから遷移する必要は無い場合）
CLIでCloud Pub/Subのサブスクリプションに問い合わせてみます。

```shell
$ gcloud pubsub subscriptions pull <作成したトピック名> --project <作成したGCPのプロジェクト名>
┌──────────────────────────────────────┬─────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────┬────────────────┐
│                 DATA                 │    MESSAGE_ID   │                                     ATTRIBUTES                                                 │     ACK_ID     │
├──────────────────────────────────────┼─────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────┼────────────────┤
│ {"temperatures": 31.719812411649684} │ 1234567890      │ credentialsId=pj-XXXXXX-1234                                                                   │ XXXXXXX....    │
│                                      │                 │ destination={"resourceUrl": "<作成したトピック名>", "service": "pubsub", "provider": "google"}      │                │
│                                      │                 │ deviceId=d-160t25jXXXXXX                                                                       │                │
│                                      │                 │ operatorId=XXXXX...                                                                            │                │
│                                      │                 │ sourceProtocol=inventory                                                                       │                │
│                                      │                 │ timestamp=1575647016294                                                                        │                │
└──────────────────────────────────────┴─────────────────┴────────────────────────────────────────────────────────────────────────────────────────────────┴────────────────┘
```

ということで、テスト送信した内容が無事GCPへ送信されていることが確認できました！

### 後片付け

以下の3ステップが必要です。

- `terraform destroy` を実行
- GCPのコンソールから該当プロジェクトを削除
- mockmockの該当プロジェクトを削除

## 参考にさせていただいたページ

勝手ながら参考にさせていただきました。大変ありがとうございます！

- [SORACOM Funnel とは | 開発者ガイド | SORACOM Developers](https://dev.soracom.io/jp/funnel/what-is-funnel/)
- [SORACOM FunnelのCloud Pub/Subアダプターを使用してGoogle Cloud Platformにデータを送信する \| Getting Started | SORACOM Developers](https://dev.soracom.io/jp/start/funnel_pubsub/)
- [Terraform × GCP 入門](https://qiita.com/donkomura/items/6289bb31fecfce2cda79)
- [Google: google_pubsub_subscription - Terraform by HashiCorp](https://www.terraform.io/docs/providers/google/r/pubsub_subscription.html)

## まとめ

mockmockからSORACOM Funnelを通してGCPのCloud Pub/Subへデータを送信してみました。
自分自身やったことがなかったので、途中で詰まってしまい「もしかして…バグ…？なぜGCPでやろうとしてしまったんだ…。」と後悔したり不安になったりしましたが、最後は無事送信できて良かったです。
また、今回の執筆を通して、SORACOM Funnelを使うことで、AWSやGCPの切り替えを設定変更だけでできるのはすごく良いなぁと実感できました。

明日は @Y_uuu の「mockmockでSORACOM Funkにデータを送るプロジェクトを作成する」です。mockmock × SORACOMの最後の記事となります。乞うご期待ください。