Meraki Dashboard APIのRate Limitを超えろ！

はじめまして。ご縁がありましてはじめてQiitaに投稿させていただきます。

初めての投稿ではMeraki Dashboard APIのRate Limitでお悩みの方に朗報であるAction Batchesについて具体的な使い方も含めてご紹介させていただきます。

####一括処理が悩ましい? Rate Limitとは？

まず、そもそもRate Limitとは何？というところからご説明します。一言でいうとRate Limitとは、秒間で受付られるAPIコール数となります。一般的にAPIを公開しているサービスにおいてはシステム保護の観点からこのような制限を設けております。

Meraki Dashboard API Rate Limit数は秒間10となっています（執筆時の2021年12月現在）。詳細は[こちら](https://developer.cisco.com/meraki/api-v1/#!rate-limit)をご確認ください。たった10？と思われるかもしれませんが、以前は秒間5だったので倍に増えています。

では、このRate Limitが悩みになるのはどうようなケースなのでしょうか。例えば、48ポートスイッチの全ポートに同じ設定を実施しようとした場合、以下のAPIエンドポイントに48回コールしなければいけません。

```
PUT /devices/{serial}/switch/ports/{portId}
```

スイッチの台数が増えれば更にコール数が増えますので、このような一括設定を行おうとするとRate Limitが処理終了時間や待ち時間考慮など大きな悩みとなります。

この問題を解決してくれるのがAction Batchesという新しいAPIエンドポイントとなります。
※新しいといっても1年以上前に公開されております。

####Action Batchesとは

Action Batchesエンドポイントは複数のAPIエンドポイントに対するアクションをバッチとして1つのコールに纏めることが可能です。メインとなるパラメータは3つで、**resource** でAPIエンドポイントを指定し、**operation** でcreateやupdateなどresourceに対するオペレーション、**body** でresourceに対してのボディをそれぞれ指示します。具体的には下記のようにスイッチポートに対してbatchTestというタグを設定するイメージです。※ここでいうタグはVLANタグではなくMeraki MSスイッチ固有のポートに対する識別子です。
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2325571/2da1f54e-3007-314b-ea80-7a6b0f52a8be.png)
1つのバッチには100個のresourceを含ませることが可能です。先ほどの48ポートの設定を考えるとアプリケーション効率は圧倒的に違ってきますね。とはいえ、無制限ではないのでAction Batchesに関する制限など詳細は[こちら](https://developer.cisco.com/meraki/api-v1/#!action-batches-overview)をご確認ください。
また、全てのAPIエンドポイントがresourceとして利用できるかというとそうではありません。執筆時の2020年12月現在では113の[resource](https://developer.cisco.com/meraki/api-v1/#!supported-resources)がサポートされ、今後も増えていきます。

####Action Batchesを試してみる
実際にAction Batchesを試してみましょう。今回試すresourceは**Meraki auth user**です。Meraki認証とも呼ばれいているMeraki auth userはWi-Fi接続で802.1X認証を利用する際に通常はオンプレにRADIUSサーバが必要ですが、Meraki CloudがRADIUSサーバ機能を提供するサービスです。ダッシュボードからは1ユーザ単位でしか作成できないため一括で作成することができませんが、Action Batchesを利用することで一括設定が可能となります。

| Group | Summary | Resource | operation |
|-----------|------------|------------|------------|
| Meraki auth user|Authorize a user configured with Meraki Authentication for a network (currently supports 802.1X, splash guest, and client VPN users, and currently, organizations have a 50,000 user cap)| /networks/{networkId}/merakiAuthUsers| create|

:::note warn
802.1X認証を利用する場合はオンプレRADIUSが推奨となります。Meraki認証はオーガナイゼーションで最大50,000ユーザまでとなりますが、ネットワーク単位では1,000ユーザ程度とお考えください。
:::

今回はCSVファイルにユーザIDとパスワードを作成してAction Batchesに渡して実行します。

```csvs:authuser.csv
email,name,password
user001@test.local,user0001,Cisco12345
user002@test.local,user0002,Cisco12345
user003@test.local,user0003,Cisco12345
user004@test.local,user0004,Cisco12345
user005@test.local,user0005,Cisco12345
user006@test.local,user0006,Cisco12345
user007@test.local,user0007,Cisco12345
```

Bodyについてはベースとなる[Create Network Meraki Auth User](https://developer.cisco.com/meraki/api-v1/#!create-network-meraki-auth-user)のフォーマットとなります。

```
{
    "email": "miles@meraki.com",
    "name": "Miles Meraki",
    "accountType": "802.1X",
    "password": "secret",
    "emailPasswordToUser": false,
    "authorizations": [
        {
            "ssidNumber": 1,
            "expiresAt": "2018-03-13T00:00:00.090210Z"
        }
    ]
}
```



上記フォーマットにしてPOSTしなければいけないため、jinja2を使って整形します。

```jinja:AuthUsers.j2
{
  "confirmed": true,
  "synchronous": true,
  "actions": [
  {%- set networkId = nw %}
  {%- for rule in data %}
  {
    "resource": "/networks/{{networkId}}/merakiAuthUsers",
    "operation": "create",
    "body": {
        "email": "{{rule.email}}",
        "name": "{{rule.name}}",
        "password": "{{rule.password}}",
        "authorizations": [
         {
            "ssidNumber": "0",
            "expiresAt": "Never"
         }
         ]
    }
  }
  {%- if loop.index < data|length -%}
  ,
  {%- endif %}
  {%- endfor %}
  ]
}
```

準備は以上となります。メインとなるPythonコードが下記となります。
必要なライブラリはインストールしておいてください。

```python:import_MerakiAuthUser.py
# -*- coding: utf-8 -*-
import sys
import requests
from jinja2 import Template, Environment, FileSystemLoader
import csv
args = sys.argv

baseUrl = "https://api.meraki.com/api/v1"
apikey = "YOUR_API_KEY"
orgid = "YOUR_ORG_ID"
netid = "YOUR_NETWORK_ID_for_import_Users"

def main():
    r = None
    headers = {'X-Cisco-Meraki-API-Key': apikey, 'Content-Type': 'application/json'}
    api_url = baseUrl + '/organizations/' + orgid + '/actionBatches'

    env = Environment(loader=FileSystemLoader('./templates', encoding='utf-8'))
    template = env.get_template('AuthUsers.j2')

    data = [i for i in csv.DictReader(open(args[1]))]
    post_data = template.render({"data": data, "nw": netid})

    try:
        r = requests.post(api_url, data=post_data.encode('utf-8'), headers=headers)
        status_code = r.status_code
        resp = r.text
        print("Status code is: " + str(status_code))
        if status_code == 201 or status_code == 202:
            print("Auth Users created successfully...")
            return resp
        else:
            print("Error occurred in POST device claim --> " + resp)
    except requests.exceptions.HTTPError as err:
        print("Error in connection --> " + str(err))
    finally:
        if r: r.close()

if __name__ == '__main__':
    main()
```

####自動化がますます簡単に
いかがでしたでしょうか。ここまで説明した内容から全く新しいものではなく、Action Batchesはもともと用意されているAPIエンドポイントをバッチ化しているインターフェースであると感じていただけたと思います。お作法であるBodyについては基となるAPIエンドポイントのBodyそのままです。これを複数作成したものを1コールで渡しているだけになります。
Rate Limitでアプリケーション効率が上がらず断念していた一括処理がAction Batchesを使えば100倍のアプリケーション効率まで向上できますので解決できます。Rate Limitに悩んでいた方はもちろんのこと、これからこのような一括処理を考えられている方は是非一度Action Batchesをお試しいただければと思います。