Meraki APIを使ってMRのHost Nameを自動設定する

今回はMerakiDashboard APIを使ってMerakiの自動設定をしたいと思います。
無線Access PointであるMRは一度に多くの数を設定することが多いのですが、Meraki Dashboard上ではほとんどの設定が自動でされるものの、Host Nameだけはどうしても手動で設定する必要があります。
MRに限らずMerakiの各デバイスのデフォルトのHost NameはMACアドレスとなっているので少し分かりにくいので何らかは設定しておきたいものです。
特にネーミングポリシーに拘りがなければ例えば対向のPoE Switchの情報(Host NameとPort番号)をLLDPで取得しMRのHost Nameに自動設定できれば良いと思い簡単なPythonスクリプトを作成しました。

また、下記のJSONのスクショはサンプルで実際に取得したデータではありませんのでご注意ください。

0. 準備編

まずはAPIを利用するための準備を行います。
「オーガナイゼーション > 設定 > 設定」へ移動します。
ダッシュボードAPIアクセス」から「APIアクセス」を有効化します。

次にAPI Keyの生成を行います。
Dashboard右上の人型アイコンからプロファイルにアクセスします。

APIにアクセスするためのAPIキーを生成します。
このAPIキーとても重要な情報で他人には絶対に明かさないように慎重に管理を行なってください。
手違いでキーが漏れてしまった場合には即そのキーを取り消して使えなくなるようにしてください。

次からはスクリプトで利用するAPIについて簡単に説明します。

1. Organizationの情報を取得(Get Organizations)

まずは生成したAPIキーに紐づくOrganizationの一覧を取得します。
https://api.meraki.com/api/v1/organizations
Organizationの名前やID等の情報を得ることができます。

複数のOrganizationを管理している場合には、複数のOrganizationの情報が返ってきますのでスクリプトではどのOrganizationの設定変更を行うのか選択できるようにしています。

2. Networkの情報を取得(Get Organizations Networks)

次に1.で選択したOrganizationからNetworkの情報を取得します。
https://api.meraki.com/api/v1/organizations/{OrganizationID}/networks
Organization内のNetworkの一覧を取得することができます。

複数のNetworkを設定されている場合は、Organizationと同様に複数の情報が返ってきます。

3. Networkに属するMerakiバイス一覧を取得(Get Network Devices)

次に2.で選択したNetworkからそのNetworkに属しているMerakiバイス一覧を取得します。
https://api.meraki.com/api/v1/networks/{NetworkID}/devices
Merakiバイスの型番やシリアル番号の取得ができます。

型番でMRが含まれるもののみを次の4で利用します。

4. MRが取得したLLDP情報を取得(Get device LLDP CDP)

3.の情報からMRのシリアル番号を使ってLLDPの情報を取得します。
これでMRの対向のSwitchのHost名とポート番号の取得ができます。
https://api.meraki.com/api/v1/devices/{Serial}/lldpcdp

LLDPで取得できるホスト名は機器の型番も含まれたものとなってしまうので、一番後ろのHost名だけを抜き出す処理を加えています。

5. MRにホスト名を設定(Update Device)

4.で取得したLLDPの情報から新しいMRのホスト名を生成します。
AP-<SwitchのHost Name>-<Port番号>
として設定します。
https://api.meraki.com/api/v1/devices/{Serial}/
3.で取得したシリアル番号、4で取得したLLDP情報を利用します。

スクリプトとしては、3. 〜 5.をMRの数分だけ繰り返していることになります。

スクリプト

少し長くなりますが、実際のスクリプトを貼り付けておきます。

APIKEYは0.で作成したものをコピペしてください。

 

import requests
import json
import time
 
APIKEY = 'XXXXXXXXXXXXX'
 
HEADERS = {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'X-Cisco-Meraki-API-Key': APIKEY
}
 
#API KEYに紐づいたOrganization一覧を取得する関数
def GetMyOrgInfo( ):
RES = requests.get( BASEURL + 'organizations' , headers=HEADERS )
RESJSON = RES.json()
return RESJSON
 
#Organization内のNetwork一覧を取得する関数
def GetNetworkInfo( ORGID ):
RES = requests.get( BASEURL + 'organizations/' + str(ORGID) + '/networks/' , headers=HEADERS )
RESJSON = RES.json()
return RESJSON
 
#Network内のDevice一覧を取得する関数
def GetDeviceList( NETID ):
RES = requests.get( BASEURL + 'networks/' + NETID + '/devices/' , headers=HEADERS )
RESJSON = RES.json()
return RESJSON
 
#CDP LLDP情報を取得する関数
def GetLLDPInfo( SERIAL ):
RES = requests.get( BASEURL + 'devices/' + SERIAL + '/lldpCdp/' , headers=HEADERS )
RESJSON = RES.json()
return RESJSON
 
#MRのHost名を設定する関数
def SetAPName( NEWNAME, SERIAL ):
PAYLOAD = {
"name" : NEWNAME,
}
RES = requests.request( 'PUT', BASEURL + 'devices/' + SERIAL , headers=HEADERS , data = json.dumps(PAYLOAD))
#API回数制限防止のためポーズ
time.sleep(0.2)
RESJSON = RES.json()
return RESJSON
###### ----- ここから実体 ----- #####
#Organizationのリストを取得
ORGINFO = GetMyOrgInfo( )
 
NUM = 0
while NUM < len(ORGINFO):
print( str(NUM) + ' : ' + ORGINFO[NUM]['name'])
NUM = NUM +1
 
#どのOrganizationを設定変更するか選択
ORGNUM = input('Which ORG do you want to configure?')
 
#Networkのリストを取得
NETWORKINFO = GetNetworkInfo( int(ORGINFO[int(ORGNUM)]['id']))
 
NUM = 0
while NUM < len(NETWORKINFO):
print( str(NUM) + ' : ' + NETWORKINFO[NUM]['name'])
NUM = NUM +1
 
#Networkを選択
NETWORKNUM = input('Which Network do you want to configure?')
 
#Network内のデバイスリスト取得
DEVICELIST = GetDeviceList(NETWORKINFO[int(NETWORKNUM)]['id'])
 
NUM = 0
while NUM < len(DEVICELIST):
#デバイスリストからMRだけを選別
if 'MR' in DEVICELIST[NUM]['model']:
#MRのLLDP情報を抽出
LLDPINFO = GetLLDPInfo(DEVICELIST[NUM]['serial'])
TARGET = ' '
#LLDPからHostNameだけを抜き出し
INDEX = LLDPINFO['ports']['wired0']['lldp']['systemName'].rfind(TARGET)
#APの名前をMR-<上流のSwitchのHostname>-<Port>にする
APNAME = 'MR-' + LLDPINFO['ports']['wired0']['lldp']['systemName'][INDEX+1:] + '-' + LLDPINFO['ports']['wired0']['lldp']['portId']
RESPONSE = SetAPName( APNAME ,  DEVICELIST[ NUM ]['serial'] )
NUM = NUM +1