SORACOM CLIで色々な操作をしてみた #soracom

よく訓練されたアップル信者、都元です。ソラコムのビッグウェーブ来てますね。ノリノリでリレーブログにエントリーしたので書いてみます。

さて、元AWSエバンジェリストの玉川さんが創業したソラコムですが、AWSと色々深い関係が垣間見えます。ソラコムのバックエンドシステムがAWS上に作られているというのは有名(?)な話ですが、システムの設計思想もAWSの流儀を引き継いています。

AWSに対する操作は、元をたどれば全てがWeb API(Webサービス)として提供されています。そのインターフェイスとしての「マネジメントコンソール」だったり「AWS CLI」だったり「AWS SDK for Java」だったりするわけです。このようなアーキテクチャでシステムを構築し、Web APIのレイヤを広く利用者に公開することによって、外部連携や自動化等のエコシステムを急速に発展させてきたという実績を持っているのがAWSです。

ソラコムもこの思想を受け継いでおり、詳細なAPIリファレンスと共にWeb APIを公開しています。当ブログでも早速検証が進んでいるようです

また、SORACOM SDK for Ruby公開していますね。自分はRubyはあまり達者じゃないのでSORACOM SDK for Javaの登場を心待ちにしております。とか言ってると将(ry

ところで、SORACOM SDK for Rubyをインストールすると、soracomコマンド(CLI)も使えるようになります。ということで試してみました。本当はSIMを登録するところからやってみたかったのですが、はやる気持ちを抑えきれず、SIMの登録とアクティベートはSORACOMユーザーコンソールから実施してしまいました。てへぺろ。

インストール

まずは「SORACOM SDK for Ruby」のインストールです。インストールはgemで一発です。ちなみに、アップデート時も同じコマンドを打てばOKです。

$ sudo gem install soracom
Password:
Fetching: soracom-1.0.3.gem (100%)
Successfully installed soracom-1.0.3
Parsing documentation for soracom-1.0.3
Installing ri documentation for soracom-1.0.3
1 gem installed

$ soracom
Commands:
  soracom auth                     # test authentication
  soracom complete                 # command list for shell completion
  soracom event_handler <command>  # Event Handler related operations
  soracom group <command>          # Group related operations
  soracom help [COMMAND]           # Describe available commands or one specific command
  soracom sim <command>            # Subscriber related operations(alias)
  soracom stats <command>          # Stats related operations
  soracom subscriber <command>     # Subscriber related operations
  soracom support                  # open support site
  soracom version                  # print version

$ soracom version
Soracom API tool v1.0.3

これでsoracomコマンドが利用可能です。ヘルプもしっかり存在し、v1.0.3がインストールできたことを確認できました。

さて、上記ヘルプではサブコマンドが10個表示されていますね。このうちhelpvesrionは上記で確認済み。simというのはsubscriberの別名のようです。

API認証

SORACOM APIは認証が必要なAPIです。SORACOMにサインアップした際のメールアドレスとパスワードによって認証する仕組みで、これらの情報は環境変数に入れておく必要があります。

soracom authコマンドは、これらの情報で認証が成功するかどうかを検証するコマンドです。実際、環境変数に何も入れずにこのコマンドを実行すると「ERROR: Could not find any credentials(email & password)」と怒られます。きちんと設定してから実行すると「authentication succeeded.」と表示されます。

$ soracom auth
testing authentication...
ERROR: Could not find any credentials(email & password)
$ export SORACOM_EMAIL='foobar@example.com'
$ export SORACOM_PASSWORD='your-password-here'
$ soracom auth
testing authentication...
authentication succeeded.
apiKey: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
operatorId: OP2222222222

コード補完

さていきなり路線をちょっと外れますが。soracomコマンドはAWS CLIと同様、サブコマンドが数多く存在するため、shellの入力補完が欲しいところです。下記のようなコマンドを実行すると、移行では補完が効くようになっています。かゆいところに手が届く感じがたまりません。

$ eval "$(soracom complete)"

.bash_profile等でAPIのクレデンシャルを設定するついでに、このコマンドも実行しておくと言いでしょう。

サポートへのアクセス

路線を外れついでにもう一つ。soracom supportコマンドを実行すると、ブラウザでサポートサイトが開くようになっています。

$ soracom support

しかもログイン済みで! スバラシイ。

screenshot_2015-10-02_18_35_29

SIMに対する操作

さて、ここがSORACOM APIのメインエリアでしょう。SIMの登録(register)、や使用開始(activate)や休止(deactivate)ができます。SORACOM用語では、SIMのことをSubscriberと呼ぶようなので、覚えておきましょう。

$ soracom subscriber
Commands:
  soracom subscriber activate --imsi=one two three                                      # activate Subscriber(SIM)s
  soracom subscriber deactivate --imsi=one two three                                    # deactivate Subscriber(SIM)s
  soracom subscriber delete_tag --imsi=one two three --tag-name=TAG_NAME                # delete tag for Subscriber(SIM)s
  soracom subscriber disable_termination --imsi=one two three                           # disable termination of Subscriber(SIM)s
  soracom subscriber enable_termination --imsi=one two three                            # enable termination of Subscriber(SIM)s
  soracom subscriber help [COMMAND]                                                     # Describe subcommands or one specific subcommand
  soracom subscriber list                                                               # list Subscriber(SIM)s
  soracom subscriber register --imsi=IMSI --registration-secret=REGISTRATION_SECRET     # register Subscriber(SIM)
  soracom subscriber set_expiry_time --expiry-time=N --imsi=one two three               # update expiry time of Subscriber(SIM)s
  soracom subscriber set_group --group-id=GROUP_ID --imsi=IMSI                          # set group of Subscriber(SIM)
  soracom subscriber terminate --imsi=one two three                                     # terminate Subscriber(SIM)s
  soracom subscriber unset_expiry_time --imsi=one two three                             # delete expiry time of Subscriber(SIM)s
  soracom subscriber unset_group --imsi=IMSI                                            # unset group of Subscriber(SIM)
  soracom subscriber update_speed_class --imsi=one two three --speed-class=SPEED_CLASS  # change speed class for Subscriber(SIM)s
  soracom subscriber update_tags --imsi=one two three --tags=key:value                  # add or update tags for Subscriber(SIM)s

私がユーザーコンソールから済ませてしまった登録操作は、残念ながら名前のAPIレスポンスを確認できません、ですが、API referenceによると、おそらくこんな感じだったのではないかと。sutatusは登録直後、何なのかは未確認です。

$ soracom subscriber register --imsi=000000000000000 --registration-secret=99999
{
  "imsi": "000000000000000",
  "msisdn": "111111111111",
  "ipAddress": null,
  "apn": "soracom.io",
  "speed_class": "s1.standard",
  "createdAt": 1443595785451,
  "lastModifiedAt": 1443676993377,
  "expiryTime": 0,
  "status": "????",
    "tags": {
      "name": "foobar"
    },
  "operatorId": "OP2222222222"
}

次にSubscriber (SIM)のアクティベートを行い、listで内容を確認します。どちらのコマンドもレスポンスの形式は同じなので、activateのレスポンスは省略しています。

$ soracom subscriber activate --imsi=000000000000000
(略)
$ soracom subscriber list
[
  {
    "imsi": "000000000000000",
    "msisdn": "111111111111",
    "ipAddress": null,
    "apn": "soracom.io",
    "type": "s1.minimum",
    "groupId": null,
    "createdAt": 1443595785451,
    "lastModifiedAt": 1443676993377,
    "expiredAt": null,
    "terminationEnabled": true,
    "status": "active",
    "tags": {
      "name": "daisuke-01"
    },
    "sessionStatus": null,
    "speedClass": "s1.minimum",
    "moduleType": "nano",
    "plan": 0,
    "expiryTime": null,
    "operatorId": "OP2222222222",
    "createdTime": 1443595785451,
    "lastModifiedTime": 1443676993377
  }
]

速度クラスの変更

その後、速度クラスはコンソールからs1.miminumに変更したので、こんな感じ。その後は、せっかくなので現状のs1.minimumをs1.slowに変更した結果を見てみます。簡単ですね。レスポンスの形式はlistと同じですので、この後のレスポンスはjqによって動きがあるプロパティのみに絞ってご紹介します。

typeとspeedClassというのが同じものを指しているように見えます。何らかの互換性維持が目的なのか、それとも何かの布石なのか。ちょっと気になりますが。

$ soracom subscriber update_speed_class --imsi=000000000000000 --speed-class=s1.minimum | jq '.[0] | {type, speedClass}'
{
  "type": "s1.minimum",
  "speedClass": "s1.minimum"
}
$ soracom subscriber update_speed_class --imsi=000000000000000 --speed-class=s1.slow | jq '.[0] | {type, speedClass}'
{
  "type": "s1.slow",
  "speedClass": "s1.slow"
}

ステータスの変更

次にステータスを変更してみましょう。activate(active=使用中にする)とdeacrivate(inactive=休止中にする)が使えます。これらの操作は冪等に実装されているようで、activeな状態に対してactivateを行っても問題ありませんでした。

$ soracom subscriber deactivate --imsi=000000000000000 | jq '.[0].status'
"inactive"

$ soracom subscriber activate --imsi=000000000000000 | jq '.[0].status'
"active"

有効期限の変更

Subscriberには有効期限(expiryTime)というプロパティがあります。デフォルトではnull(無期限)です。

期限に到達したSIMは、それ以降に新規セッションを開始できなくなります。既に接続中のセッションが切断されたり、ステータスがinactiveになるわけではありません。この有効期限は下記のように設定できます。有効期限の指定はエポックミリ秒なので、ちょっと強引なことをしてますが。下記の例では15秒後に有効期限を設定しています。

$ soracom subscriber set_expiry_time --expiry-time=`date -v+15S +%s`000 --imsi=000000000000000 | jq '.[0].expiryTime'
1444009151000

一度設定した有効期限は下記でnull(無期限)に設定できます。これらの操作も冪等でした。このコマンドは、レスポンスの型が異なるんですね。

$ soracom subscriber unset_expiry_time --imsi=000000000000000
[
  {
    "imsi": "000000000000000",
    "result": "success"
  }
]

タグの付与

リソースに対するメタデータとして付与する「タグ」という考え方も、AWSの影響を色濃く受けた仕組みに思います。key-value形式で利用者の好きな情報を付与できるのは非常に便利ですね。SIMに付けた名前(任意につけられる)も、タグとして実装されています。

$ soracom subscriber list | jq '.[0].tags'
{
  "name": "daisuke-01"
}

$ soracom subscriber update_tags --imsi=000000000000000 --tags=foo:bar | jq '.[0].tags'
{
  "foo": "bar",
  "name": "daisuke-01"
}

$ soracom subscriber delete_tag --imsi=000000000000000 --tag-name=foo
[
  {
    "imsi": "000000000000000",
    "result": "success"
  }
]

グループの作成と設定

SORACOMでは、SIMをグループ化して管理する機能があります。単純にフォルダ分けして整理するためにも使えますが、グループ内のSIMに対して一括で変更を適用するために利用できるようです。

$ soracom group
Commands:
  soracom group create                                                                          # create group
  soracom group delete_configuration --group-id=GROUP_ID --name=NAME --namespace=NAMESPACE      # delete configuration parameter
  soracom group delete_group --group-id=GROUP_ID                                                # delete a group
  soracom group delete_tag --group-id=GROUP_ID --name=NAME                                      # delete group tag
  soracom group help [COMMAND]                                                                  # Describe subcommands or one specific subcommand
  soracom group list                                                                            # list groups
  soracom group list_subscribers --group-id=GROUP_ID                                            # list subscriber in a group
  soracom group update_configuration --group-id=GROUP_ID --namespace=NAMESPACE --params=PARAMS  # update configuration parameter
  soracom group update_tags --group-id=GROUP_ID --tags=TAGS                                     # update group tags

初期状態ではグループは1つも存在しません。

$ soracom group list
[

]

group createコマンドによりグループの新規作成ができます。このコマンドでは「無名」のグループを作るだけなので、引き続きタグとして名前を付ける必要があります。group update_tagssubscriber update_tagsでは--tagsパラメータの指定方法が異なるのは要注意です。

$ soracom group create
{
  "operatorId": "OP2222222222",
  "groupId": "xxxx90a6-xxxx-xxxx-xxxx-c6aexxxxb029",
  "createdAt": 1444007481817,
  "lastModifiedAt": 1444007481817,
  "configuration": {
  },
  "tags": {
  },
  "createdTime": 1444007481817,
  "lastModifiedTime": 1444007481817
}

$ soracom group update_tags --group-id=xxxx90a6-xxxx-xxxx-xxxx-c6aexxxxb029 --tags='[{"tagName":"name","tagValue":"private"}]'
{
  "operatorId": "OP2222222222",
  "groupId": "xxxx90a6-xxxx-xxxx-xxxx-c6aexxxxb029",
  "createdAt": 1444007481817,
  "lastModifiedAt": 1444010090833,
  "configuration": {
  },
  "tags": {
    "name": "private"
  },
  "createdTime": 1444007481817,
  "lastModifiedTime": 1444010090833
}

さて、上記で作成したグループに、subscriberを所属させ、そして離脱させてみます。

$ soracom subscriber list | jq '.[0].groupId'
null

$ soracom subscriber set_group --group-id=xxxx90a6-xxxx-xxxx-xxxx-c6aexxxxb029 --imsi=000000000000000
{
  "imsi": "000000000000000",
(略)
  "groupId": "xxxx90a6-xxxx-xxxx-xxxx-c6aexxxxb029",
(略)
}

$ soracom subscriber unset_group --imsi=000000000000000
{
  "imsi": "000000000000000",
(略)
  "groupId": null,
(略)
}

利用統計の参照

statsサブコマンドは各SIMの利用統計を得るコマンドです。

$ soracom stats
Commands:
  soracom stats export_air_usage            # export air usage for all Subscriber(SIM)s in csv format
  soracom stats export_beam_usage           # export beam usage for all Subscriber(SIM)s in csv format
  soracom stats get_air_usage --imsi=IMSI   # get air usage per Subscriber(SIM)
  soracom stats get_beam_usage --imsi=IMSI  # get beam usage per Subscriber(SIM)
  soracom stats help [COMMAND]              # Describe subcommands or one specific subcommand

export_*_usageでは、下記のようにCSV形式で各SIM毎の利用状況を取得できます。

$ soracom stats export_air_usage
imsi,date,type,uploadByteSizeTotal,uploadPacketCountTotal,downloadByteSizeTotal,downloadPacketCountTotal,name,group:groupId,group:name
000000000000000,20151004,s1.standard,16111,119,20940,119,daisuke-01,xxxx90a6-xxxx-xxxx-xxxx-c6aexxxxb029,private

また get_*_usageではより細かい利用状況がJSON形式でやってきます。中身については追い切れませんでした。いずれまた!

$ soracom stats get_air_usage --imsi=000000000000000
[
  {
    "date": "2015-10-04T12:07:52.489",
    "unixtime": 1443960472,
    "dataTrafficStatsMap": {
      "s1.standard": {
        "uploadByteSizeTotal": 1234,
        "downloadByteSizeTotal": 1357,
        "uploadPacketSizeTotal": 8,
        "downloadPacketSizeTotal": 8
      }
    }
  },
  {
    "date": "2015-10-04T12:12:52.504",
    "unixtime": 1443960772,
    "dataTrafficStatsMap": {
      "s1.standard": {
        "uploadByteSizeTotal": 0,
        "downloadByteSizeTotal": 0,
        "uploadPacketSizeTotal": 0,
        "downloadPacketSizeTotal": 0
      }
    }
  },
(略)
]

イベントハンドラの設定

SORACOMでは、通信量(日次や月次等)が一定量を超えたら、メールで通知を行ったり、通信速度を制限したりできます。そのような監視の仕組みを取り扱うのがevent_handlerです。

$ soracom event_handler
Commands:
  soracom event_handler create                          # create event handler
  soracom event_handler delete --handler-id=HANDLER_ID  # delete event handler
  soracom event_handler help [COMMAND]                  # Describe subcommands or one specific subcommand
  soracom event_handler list                            # list event handlers
  soracom event_handler update --handler-id=HANDLER_ID  # update event handler configuration

初期状態では特に何も設定していないので、カラッポですね。

$ soracom event_handler list
[

]

ただ、この設定操作をCLIから行うのは、ダイスケ的にだいぶ敷居が高いので、ここではユーザーコンソールから設定した値を確認するだけで勘弁してください。

screenshot_2015-10-05_11.31.06

$ soracom event_handler list
[
  {
    "handlerId": "2247xxxx-xxxx-xxxx-xxxx-b093xxxxb4dd",
    "targetImsi": null,
    "targetOperatorId": "OP2222222222",
    "targetTag": null,
    "targetGroupId": null,
    "name": "Prefixed event handler",
    "description": null,
    "ruleConfig": {
      "type": "DailyTrafficRule",
      "properties": {
        "inactiveTimeoutDateConst": "BEGINNING_OF_NEXT_DAY",
        "limitTotalTrafficMegaByte": "10"
      }
    },
    "status": "active",
    "actionConfigList": [
      {
        "type": "SendMailToOperatorAction",
        "properties": {
          "executionDateTimeConst": "IMMEDIATELY",
          "message": "対象SIM ${imsi} \n\n利用状況を確認してください。",
          "title": "SIMの日次通信量が10MiBを超えています"
        }
      }
    ]
  }
]

これをCLIで設定するのは、だいぶ深い理解が必要っぽいのがお分かりいただけるかと…。ただ、targetTag要素等を見るに、特定のタグが付いたSubscriberに対してのみ監視を行うような仕組みも設定できそうですね。だいぶ細かい制御が可能なようなので、色々な使い方が期待できますね。

SubscriberのTerminateと保護

Subscriberのterminateとは そのSIMの解約 です。この操作をしたSIMは契約が終了し、今後使うことはできません。再登録することもできませんので、一般的には物理的に破壊してポイするものです。

そんな危険な操作がCLIから出来てしまうのも危険ですが、CLIから出来ないというのも不便です。そんな時のためのTermination protectionですね!EC2でもおなじみのアレです。

$ soracom subscriber disable_termination --imsi=000000000000000 | jq '.[0].terminationEnabled'
false

$ soracom subscriber enable_termination --imsi=000000000000000 | jq '.[0].terminationEnabled'
true

$ soracom subscriber terminate --imsi=000000000000000
You may not revert terminate opereation. Please add "--confirm YES" if you are sure.

さすがに、気軽にはTerminateさせてくれません。でも大丈夫、プロテクトがenableの時、どんなレスポンスをするのか見てみるだけだから。

$ soracom subscriber terminate --imsi=000000000000000 --confirm YES
[
  {
    "imsi": "000000000000000",
    "msisdn": "111111111111",
    "ipAddress": null,
    "apn": "soracom.io",
    "type": "s1.slow",
    "groupId": "xxxx90a6-xxxx-xxxx-xxxx-c6aexxxxb029",
    "createdAt": 1443595785451,
    "lastModifiedAt": 1444013249880,
    "expiredAt": null,
    "terminationEnabled": true,
    "status": "terminated",
    "tags": {
      "name": "daisuke-01"
    },
    "sessionStatus": null,
    "speedClass": "s1.slow",
    "moduleType": "nano",
    "plan": 0,
    "expiryTime": null,
    "operatorId": "OP2222222222",
    "createdTime": 1443595785451,
    "lastModifiedTime": 1444013249880
  }
]

あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛

screenshot_2015-10-05_11.51.07

手記はここで途切れている。諸君においては「terminationのenabled」と「termination protectionのenabled」の違いを深く認識しておいて頂きたく。合掌。

.

.

.

.

.

.

追記

えーーと。SORACOMのローンチから約1週間経ちますが、実際にterminateしてしまったSIMというのは貴重なサンプルかと思います。引き続きいくつか試してみました。

一覧には現在も表示が続いています。が、この情報は永遠には残らないとのことです。いつ消えるのかは、神のみぞ。

$ soracom subscriber list
[
  {
    "imsi": "000000000000000",
    "msisdn": "111111111111",
    "ipAddress": null,
    "apn": "soracom.io",
    "type": "s1.slow",
    "groupId": "xxxx90a6-xxxx-xxxx-xxxx-c6aexxxxb029",
    "createdAt": 1443595785451,
    "lastModifiedAt": 1444022738336,
    "expiredAt": null,
    "terminationEnabled": true,
    "status": "terminated",
    "tags": {
      "name": "daisuke-01"
    },
    "sessionStatus": null,
    "speedClass": "s1.slow",
    "moduleType": "nano",
    "plan": 0,
    "expiryTime": null,
    "operatorId": "OP0067490990",
    "createdTime": 1443595785451,
    "lastModifiedTime": 1444022738336
  }
]

もちろん、一縷の望みを託し activate を試みるも、砕け散ります。

$ soracom subscriber activate --imsi=000000000000000
[
  {
    "imsi": "000000000000000",
    "code": "SEM0040",
    "message": "The specified subscriber has been terminated. You cannot change the status."
  }
]

そして、terminated状態でもタグの編集はできるようです。へえ。同様に、グループへの参加や離脱等の操作も行えます。とは言え、いつ消えてしまうか分からんものですが。

$ soracom subscriber update_tags --imsi=000000000000000 --tags=foo:bar | jq '.[0].tags'
{
  "foo": "bar",
  "name": "daisuke-01"
}

その他、terminate済みのSIMに対してやってみたいことがあれば、Twitter等でリクエストを頂ければ試してみるかもしれません。お待ちしております。