サポートセンターホーム


Cisco Meraki モニタリング

概要

LogicMonitorのCiscoMerakiモニター用のすぐに使用可能な監視:

  • ハイブリッドAPI / SNMPデータ収集アプローチを使用したネットワークごとのレベルのMerakiデバイス
  • 組織ごとのAPI使用量とデバイス数

必須条件

LogicMonitor Collector EA29.1xx以降

セットアップ要件

API構成

Meraki DashboardAPIへのアクセスを有効にする必要があります。 Meraki環境で、次の場所に移動します 組織 > 設定 > ダッシュボードAPIアクセスを選択し、 CiscoMerakiダッシュボードAPIへのアクセスを有効にする チェックボックスをオンにします。

APIアクセスを有効にした後、に移動します 私のプロフィール ページを作成し、APIキーを生成します。 APIキーは、LogicMonitor内のプロパティに割り当てられます。 APIキーが生成されたら、必ず安全な場所にコピーしてください。

見る CiscoのMerakiダッシュボードAPIドキュメント APIアクセスを有効にしてAPIキーを生成する手順については。

SNMP構成

SNMP v2cまたはv3は、Meraki CloudControllerで有効にする必要があります。 見る CiscoのSNMPの概要と構成のドキュメント 手順を参照してください。

Merakiデバイスグループを作成する

[リソース]ページから、Merakiデバイスグループを作成し、それに次のプロパティを割り当てます。

プロパティ製品説明
meraki.api.keyMeraki APIキー(前のセクションで説明したように、キーを生成し、APIを有効にする必要があります)
snmp.port16100
snmp.versionLogicMonitorはデバイス自体ではなく、クラウドコントローラーにクエリを実行するため、SNMPを利用する他の監視操作の場合のように、SNMPバージョンをこのプロパティに自動的に割り当てることはできません。 対応するSNMPバージョン(「v2c」または「v3」のいずれか)をこのプロパティに手動で割り当てるようにしてください。
snmp.community(v2cのみ)
snmp.security(v3のみ)
これらの値はMerakiによって生成され、「o /」で始まります。
その他のSNMPクレデンシャル
残りのSNMPクレデンシャルを確立するために必要なプロパティは、使用されているSNMPバージョンによって異なります。 詳細については、を参照してください。 認証資格情報の定義.

デバイスグループの作成の詳細については、を参照してください。 デバイスグループの追加.

モニタリングへのリソースの追加

CiscoMerakiホストをモニタリングに追加します。 NetScanを使用して、関連するすべてのデバイスを監視に自動的に追加する(およびいくつかの必要なデバイスプロパティを自動割り当てる)か、デバイスを手動で監視に追加することができます。

NetScanを介したリソースの追加

高度なNetScanを介して、すべてのMerakiネットワーク、組織、およびメインのapi.meraki.comデバイスを自動的に追加できます。 高度なNetScanを作成して実行する手順については、を参照してください。 NetScanの作成.

NetScanに対して次の構成が設定されていることを確認してください。

  • 次のGroovyスクリプトを埋め込みます(このスクリプトを埋め込む必要があるテキストボックスにアクセスするには、[デバイスを検出するためのスクリプトまたはcsvをアップロードする]を選択します。 方法 フィールドのドロップダウンメニューを選択し、 Groovyスクリプトを埋め込む 動的に表示されるスクリプトオプションのオプション)。

    注意: 必ず代用してください INSERT API TOKEN HERE このスクリプトの上部にあるプレースホルダーテキストと実際のAPIトークン。

/*******************************************************************************
 *  © 2007-2021 - LogicMonitor, Inc. All rights reserved.
 ******************************************************************************/

import com.santaba.agent.util.Settings
import groovy.json.JsonOutput
import groovy.json.JsonSlurper

// Set this variable to meraki API token.
def token = ""

// Optionally, create a list of organizations (e.g. ["1243","2343","3564","4355"])
// Setting this variable will only discover networks on those orgs.
def orgsAllowed = null

collectorCache = null
try {
    collectorCache = this.class.classLoader.loadClass("com.santaba.agent.util.script.ScriptCache").getCache()
}
catch (ClassNotFoundException ignored) {}
debug = false

orgs = cachedHttpGet(token, "/organizations")

orgs.each { org ->
    def orgId = org.id

    // Filter in only allowed orgs if it's defined.
    if (orgsAllowed != null) {
        if (!orgsAllowed.contains(orgId)) {
            return
        }
    }

    def orgName = org.name
    def networks = []
    def devices = []

    try {
        networks = cachedHttpGet(token, "/organizations/${orgId}/networks")
        devices = cachedHttpGet(token, "/organizations/${orgId}/devices")
    } catch (Exception error) {
            if (debug) println error.message
            return
    }

    networks.each { network ->
        def networkId = network.id

        // Check if this network has any devices and avoid reporting deviceless networks.
        def networkDevices  = devices.findAll{it.networkId == networkId}
        if (networkDevices.size() == 0) {
            return
        }

        def networkName = network.name
        def networkTags = network.tags
        def hostName = "${orgName.replaceAll('\\W', '')}.${networkName.replaceAll('\\W', '')}.invalid"
        def displayName = "Meraki Network: ${networkName}"

        println "${hostName}##${displayName}##meraki.org.name=${orgName}##meraki.org.id=${orgId}##meraki.api.key=${token}##meraki.network.id=${networkId}##meraki.network.name=${networkName}##meraki.network.tags=${networkTags}##meraki.network.type=${network.type}"
    }

    // Only add orgs if they have networks.
    if (networks.size() > 0) {
        println "${orgName.replaceAll('\\W', '')}.invalid##Meraki Org: ${orgName}##meraki.org.name=${orgName}##meraki.org.id=${orgId}##meraki.api.key=${token}"
    }
}

println "api.meraki.com##api.meraki.com##meraki.api.key=${token}"

return 0


def cachedHttpGet(String token, String endpoint, Map args=[:], String serviceUrl="https://api.meraki.com/api/v0", Integer expirySecs=600) {
    if (collectorCache) {
        def cacheKey = "CiscoMeraki.APICache:${token}-${composeUrl(serviceUrl, endpoint, args)}"

        LMDebugPrint("Trying cache for a recent answer to ${endpoint}")

        def cachedResponse = collectorCache.get(cacheKey)

        if (cachedResponse) {
            LMDebugPrint("Cached response found, returning ${cachedResponse.size()} bytes")
            return (new JsonSlurper()).parseText(cachedResponse)
        }
        else{
            LMDebugPrint("No cached response found.")
            Integer retryCount = 0

            while (retryCount < 5) {
                retryCount++
                // We are in the lock, lets get the data, update the cache and
                if(_cacheAcquireLock(cacheKey, 30)) {
                    try {
                        expirySecs = expirySecs * 1000 // Convert to ms.
                        cachedResponse = httpGet(token, endpoint, args, serviceUrl)
                        collectorCache.set(cacheKey, JsonOutput.toJson(cachedResponse), expirySecs)

                        return cachedResponse
                    }
                    finally {
                        _cacheReleaseLock(cacheKey)
                    }
                }
                else {
                    cachedResponse = collectorCache.get(cacheKey)
                    if (cachedResponse) {
                        return (new JsonSlurper()).parseText(cachedResponse)
                    }
                }

                sleep(1000) // Wait for the other thread to finish or time out.
            }
        }
    }

    else {
        return httpGet(token, endpoint, args, serviceUrl)
    }
}

boolean _cacheAcquireLock(String cacheKey, Integer timeOutSecs) {
    String lockKey = "${cacheKey}:Lock"
    String lockValue = collectorCache.get(lockKey)
    def now = (new Date()).getTime()
    if (lockValue == null) {
        lockValue = (now + timeOutSecs).toString()
        collectorCache.set(lockKey, lockValue, (timeOutSecs * 1000))
        return true
    }
    else {
        return false
    }
}

def _cacheReleaseLock(String cacheKey) {
    String lockKey = "${cacheKey}:Lock"
    collectorCache.remove(lockKey)
}

def httpGet(token, endpoint, Map args=[:], serviceUrl="https://api.meraki.com/api/v0") {
    def retryCount = 0

    while (true) {
        if (retryCount > 10) throw new Exception("Unable to get ${endpoint} after ${retryCount} retries, giving up")

        def request = rawHttpGet(token, endpoint, args, serviceUrl)
        def responseCode = request.getResponseCode()
        LMDebugPrint("Status code: ${responseCode}")

        if (responseCode == 200) {
            String content = request.content.text
            LMDebugPrint("Content length: ${content.size()} bytes")
            def payload = new JsonSlurper().parseText(content)

            String links = request.getHeaderField('link')
            if (links) {
                /* Unpack a header in this form:
                <https://nXXX.meraki.com/api/v1/organizations/00000000/devices?perPage=100&startingAfter=0000-0000-0000>; rel=first,
                <https://nXXX.meraki.com/api/v1/organizations/00000000/devices?endingBefore=XYZ-XYXX-XYZZ&perPage=100>; rel=prev,
                <https://nXX.meraki.com/api/v1/organizations/000000000/devices?endingBefore=ZZZZ-ZZZZ-ZZZZ&perPage=100>; rel=last
                 */
                links.split(',').each { link ->
                    def rel = link.split(';')[1].split('=')[1]

                    if (rel == 'next') {
                        def nextEndpoint = link.split(';')[0].strip()[1..-2]
                        sleep(200) // Sleep 1/6th of a second to avoid triggering the throttling.
                        payload += httpGet(token, "", [:], nextEndpoint)
                    }
                }
            }

            return payload
        }
        else if (responseCode == 429) {
            def retryIn = request.getHeaderField('Retry-After')

            if (retryIn == null) retryIn = 5
            else retryIn = retryIn.toInteger()

            LMDebugPrint("Sleeping and retrying in ${retryIn} ms after recieving a 429 response")
            sleep(retryIn * 1000)
        }
        else {
            throw new Exception("Server return HTTP code ${responseCode} from ${endpoint}")
        }
        retryCount++
    }
}



static String composeUrl(String serviceUrl, String endpoint, Map args) {
    def url = serviceUrl+endpoint

    if (args) {
        def encodedArgs = []
        args.each{ k,v ->
            encodedArgs << "${k}=${URLEncoder.encode(v.toString(), "UTF-8")}"
        }
        url += "?${encodedArgs.join('&')}"
    }
    return url
}

def rawHttpGet(String token, String endpoint, Map args=[:],serviceUrl="https://api.meraki.com/api/v0") {
    def headers = ["X-Cisco-Meraki-API-Key": token.toString(),
                   "Accept": "application/json"]

    url = composeUrl(serviceUrl, endpoint, args)

    def request = null
    def proxyInfo = getProxyInfo()

    if (proxyInfo) {
        request = url.toURL().openConnection(proxyInfo)
    }
    else {
        request = url.toURL().openConnection()
    }

    headers.each { request.addRequestProperty(it.key, it.value)}
    LMDebugPrint("GET ${url}")

    return request
}

def getProxyInfo() {
    if (Settings.getSetting("proxy.enable").toBoolean()) {
        return new Proxy(Proxy.Type.HTTP,
                new InetSocketAddress(Settings.getSetting("proxy.host"), Settings.getSetting("proxy.port")?.toInteger()))
    }

    return null
}

def LMDebugPrint(message) {
    if (debug) {
        println(message.toString())
    }
}
Groovy
  • メディア デフォルトグループ フィールド(スクリプトテキストボックスの後に表示されます)で、以前に作成したCiscoMerakiデバイスグループを指定します。
  • 注意: NetScanを実行する前に、SNMPクレデンシャルとMerakiキーがこのグループのプロパティとして設定されていることを確認してください。 詳細については、を参照してください。 Merakiデバイスグループを作成する

    手動で

    Merakiデバイスを手動で監視に追加できます。 追加できるMerakiデバイスには次のXNUMXつのタイプがあります。

    • ネットワークデバイス
    • 組織デバイス
    • MerakiAPIデバイス

    これらのデバイスを追加するときは、前に作成したデバイスグループにそれらを割り当てます。 監視にリソースを手動で追加する手順については、を参照してください。 デバイスの追加.

    ネットワークデバイス

    ネットワークデバイスは、特定のネットワークのデバイスごとおよびインターフェイスごとのデータを報告します。

    • ネットワークデバイスのホスト名( IPアドレス/ DNS名 フィールド)は「.invalid」で終わる必要があります。
    • ネットワーク固有のプロパティは、で説明されているように、デバイスに割り当てる必要があります リソースへのプロパティの割り当て このサポート記事のセクション。
    組織デバイス

    組織デバイスは、特定の組織のネットワークごとのデバイス数とAPI使用統計を報告します。

    • 組織デバイスのホスト名( IPアドレス/ DNS名 フィールド)は「.invalid」で終わる必要があります。
    • で説明されているように、組織固有のプロパティをデバイスに割り当てる必要があります リソースへのプロパティの割り当て このサポート記事のセクション。
    MerakiAPIデバイス

    Meraki APIデバイスは、アカウント上のすべての組織のネットワークごとのデバイス数とAPI使用統計を報告します。

    • Meraki APIデバイスのホスト名( IPアドレス/ DNS名 フィールド)は「api.meraki.com」である必要があります。

    リソースへのプロパティの割り当て

    SNMPに加えて meraki.api.key プロパティ(で説明されているように、グループレベルで割り当てることをお勧めします Merakiデバイスグループを作成する このサポート記事のセクション)、次のプロパティもLogicMonitor内のMerakiデバイスで設定する必要があります。

    注意: NetScanを介して監視にリソースを追加した場合、これらのプロパティはすでに割り当てられています。 監視にリソースを手動で追加した場合は、これらのプロパティを手動で設定する必要があります。 プロパティを手動で設定する手順については、を参照してください。 リソースとインスタンスのプロパティ.

    プロパティ製品説明
    meraki.org.idこのプロパティは、組織のデバイスにのみ設定してください。 組織とそれぞれのIDのリストについては、次のWebサイトをご覧ください。 https://developer.cisco.com/meraki/api/#!get-organizations.*
    meraki.network.idこのプロパティは、ネットワークデバイスでのみ設定してください。 ネットワークとそれぞれのIDのリストについては、次のWebサイトをご覧ください。 https://developer.cisco.com/meraki/api/#!get-organization-networks。 ネットワークを表示する組織の組織IDを必ず入力してください。*

    *必ず設定してください X-Cisco-Meraki-API-Key https://developer.cisco.com/meraki/apiからAPIリクエストを実行する場合は、APIキーのヘッダー。

    複数の組織

    一部のMeraki構成には、SNMPクレデンシャルが異なる複数の組織を含めることができます。 このような場合、組織に属するリソースは、組織ごとに動的グループを作成し、そこに特定のプロパティを割り当てることでグループ化できます。

    LogicModulesのインポート

    LogicMonitorパブリックリポジトリから、にリストされているすべてのCisco MerakiLogicModuleをインポートします。 パッケージ内のLogicModules このサポート記事のセクション。 これらのLogicModuleがすでに存在する場合は、最新バージョンであることを確認してください。

    LogicModuleがインポートされると(以前のセットアップ要件がすべて満たされていると仮定して)、Merakiデータソースのスイートが自動的にデータの収集を開始します。

    レガシーデータソースからの移行

    2020年XNUMX月、LogicMonitorはCisco MerakiDataSourcesの新しいスイートをリリースしました。 新しいデータソースには、監視範囲の拡大や将来のスケーラビリティとサポートのための効率の向上など、いくつかの利点があります。

    これらの新しいデータソースのリリースは、次のレガシーMerakiデータソースを非推奨にするのに役立ちます。

    • Meraki_CloudController_DeviceInventory
    • Meraki_MR_Interfaces
    • Meraki_MR_Stats
    • Meraki_MS_Stats
    • Meraki_MX_Interfaces
    • Meraki_MX_Stats
    • Meraki_Z_Interfaces
    • Meraki_Z_Stats

    これらのレガシーデータソースのいずれかを使用して現在Merakiデバイスを監視している場合、新しいデータソースをインポートしてもデータが失われることはありません。 これは、モジュールの上書きを排除するためにデータソース名が変更されたためです。

    ただし、データソースの両方のセットがアクティブである限り、重複データを収集し、重複アラートを受信します。 このため、新しいデータソースのセットをインポートし、環境で意図したとおりに機能していることを確認した後、上記のデータソースを無効にすることをお勧めします。

    データソースを無効にすると、ホストへのクエリとアラートの生成が停止しますが、すべての履歴データは保持されます。 ある時点で、レガシーデータソースを完全に削除したい場合がありますが、削除するとすべての履歴データが失われるため、この移動を慎重に検討してください。 データソースの無効化の詳細については、を参照してください。 データソースまたはインスタンスの監視を無効にする.

    パッケージ内のLogicModules

    Cisco Meraki用のLogicMonitorのパッケージは、次のLogicModuleで構成されています。 完全にカバーするには、これらのLogicModuleがすべてLogicMonitorプラットフォームにインポートされていることを確認してください。

    お名前種類製品説明
    addCategory_Meraki_APIプロパティソースホストがMerakiAPIアクセス用に構成されているかどうかを識別し、さまざまなシステム自動プロパティを追加し、「MerakiAPIOrg」と「NoPing」の値をに追加します。 system.categories プロパティ。
    Cisco_Meraki_SwitchesデータソースMerakiSwitchクライアントの接続と動作ステータスを監視します。
    注意: 現在、スイッチ名の代わりにスイッチのシリアル番号が表示されています。
    Cisco_Meraki_Switch_InterfacesデータソースネットワークごとのレベルでMerakiSwitchインターフェイスのデータスループットとパケット送信を監視します。
    注意: 現在、スイッチ名の代わりにスイッチのシリアル番号が表示されています。
    Cisco_Meraki_SecurityAppliancesデータソースMeraki SecurityApplianceクライアントの接続と動作ステータスを監視します。
    Cisco_Meraki_SecurityAppliance_Interfacesデータソースネットワークごとのレベルで、Meraki SecurityApplianceインターフェイスのデータスループットとパケット送信を監視します。
    Cisco_Meraki_Licensingデータソース特定の組織のライセンスステータスを報告します。
    Cisco_Meraki_UplinkLossAndLatencyデータソース組織内のすべてのMXのアップリンク損失と遅延を返します。
    Cisco_Meraki_UplinkApplianceStatusデータソース組織内のすべてのMerakiMXおよびZシリーズアプライアンスのアップリンクステータスを一覧表示します。
    Cisco_Meraki_OrgDeviceCountデータソース組織ごとのMerakiデバイスの数。
    Cisco_Meraki_DeviceCountデータソースネットワークごとのレベルでのMerakiデバイスの数と合計数。
    Cisco_Meraki_API使用法データソース組織ごとにMerakiAPIの使用状況をカウントします。
    Cisco_Meraki_GatewaysデータソースMeraki TeleworkerGatewayクライアントの接続と動作ステータスを監視します。
    Cisco_Meraki_Gateway_Interfacesデータソースネットワークごとのレベルで、Meraki TeleworkerGatewayインターフェイスのデータスループットとパケット送信を監視します。
    Cisco_Meraki_AccessPointsデータソースMerakiアクセスポイントのクライアント接続と動作ステータスを監視します。
    注意: 現在、アクセスポイント名の代わりにアクセスポイントのシリアル番号が表示されています。
    Cisco_Meraki_AccessPoint_Interfacesデータソースネットワークごとのレベルで、Merakiアクセスポイントインターフェイスのデータスループットとパケット送信を監視します。
    注意: 現在、アクセスポイント名の代わりにアクセスポイントのシリアル番号が表示されています。

    このパッケージのデータソースによって追跡されるさまざまなメトリックに静的データポイントのしきい値を設定する場合、LogicMonitorはテクノロジ所有者のベストプラクティスのKPI推奨事項に従います。 必要に応じて、これらの事前定義されたしきい値を調整して、環境固有のニーズを満たすことをお勧めします。 データポイントのしきい値の調整の詳細については、を参照してください。 データポイントの静的しきい値の調整.

    記事上で