ジュニパーミストモニタリング

最終更新日: 10 年 2024 月 XNUMX 日

LogicMonitor は、Juniper Mist 組織、サイト、およびデバイスの監視を提供します。 組織の健全性、サイト、サイトによって生成されたトラフィック、および Juniper Mist アクセス ポイント、EX シリーズ スイッチ、セッション、スマート ルーターなどの Juniper Mist が管理するデバイスを監視できます。 の ジュニパーミスト API サイトのデバイス統計とデータを取得するために使用されます。

要件

Juniper Mist リソースの追加

次の方法を使用して、Juniper Mist リソースを追加できます。

  • (推奨) 各 Mist 組織サイトのデバイス グループの下にデバイスを作成する高度な NetScan。詳細については、を参照してください。 ネットスキャンとは.
  • 手動で

Advanced NetScan を使用して Juniper Mist リソースを追加する (推奨)

Juniper Mist で管理されたデバイスを追加するための推奨される方法は、 強化されたスクリプト ネットスキャン この記事で LogicMonitor が提供する Groovy スクリプトを使用します。 特定の Juniper Mist 組織に対して、拡張スクリプト Netscan は、Mist 組織と各 Mist サイトのグループ、および関連するグループ内の各 Mist 管理デバイスのリソースを作成します。

  1. Juniper Mist LogicModule をインストールします。 詳細については、「」を参照してください。 Juniper Mist ロジックモジュール.
  2. LogicMonitorで、次の場所に移動します リソース > Add > 複数のデバイス > 高度なネットスキャン.
    [高度な NetScan の追加] ページが表示されます。
  3. 入力します 名前  この NetScan に関連付けるたとえば、ジュニパー ミスト。
  4. 現在地に最も近い コレクタ これにより、NetScan が実行されます。
    デフォルトでは、NetScan は NetScan を実行するコレクタに新しいリソースを割り当てます。 後で [プロパティ] でこの動作をオーバーライドし、複数のコレクター グループを使用できます (スケールまたは論理接続用)。 グループ化されていないコレクタまたはフェールオーバーのあるコレクタ グループのいずれかを選択します。
  5. 選択 強化されたスクリプト NetScan   方法 ドロップダウンリスト。
  6. ノーザンダイバー社の 強化されたスクリプト セクション、選択 デバイスの資格情報 > このスキャンにカスタム資格情報を使用する.
  7. 次のプロパティを追加します。 プロパティは、必要な Juniper Mist API クレデンシャルを NetScan に提供し、NetScan がリソースを作成および編成する方法と場所を変更します。
プロパティ必須?
ミスト.api.キーミスト API トークン有り
ミスト.api.org霧の組織ID有り
ミスト.api.org.名あなたのミストの組織名。 これは、Juniper Mist のルート リソース グループの名前になるか、最上位の子リソース グループの名前になります。 mist.api.org.folder プロパティを使用して代替ルート フォルダーを指定します。いいえ
ミスト.api.org.フォルダーこの NetScan が作成または既存の場合に使用する LogicMonitor リソース グループの名前。 値は、ネストされた子フォルダーにすることができます。 例えば、 フォルダ/フォルダ/フォルダ.いいえ
ミスト.api.org.sites含めるサイト名をコンマで区切って指定します (その他は除外されます)。いいえ
ミスト.api.org.collector.sites.csv
デフォルトでは、NetScan によって作成された新しいリソースは、NetScan を実行するコレクタに割り当てられます。 このプロパティは、CSV ファイルを使用してデフォルトの動作をオーバーライドし、Mist サイトと LM コレクターの名前に基づいて、Mist デバイスを目的のコレクターに割り当てます。 CSV ファイルは、NetScan を実行するコレクタに保存する必要があります。

Linux: /usr/local/logicmonitor/agent/bin
Windows: C:\Program Files\LogicMonitor\Agent\bin

詳細については、を参照してください。 ミスト サイトを LM Envision コレクターにマッピングする.
いいえ
ミスト.api.url代替地域の URL には次のものがあります。

https://api.eu.mist.com/api/v1/
https://api.ac2.mist.com/api/v1/
https://api.gc1.mist.com/api/v1/
いいえ
lmaccess.id
OR
ロジックモニター.アクセス.id
ポータルにリソースを追加する前に NetScan で重複リソースを検索するための LogicMonitor API アクセス ID。 ポータル監視の詳細については、次を参照してください。 LogicMonitorポータルモニタリング.有り
lmaccess.key
OR
ロジックモニター.アクセス.キー
ポータルにリソースを追加する前に NetScan で重複リソースを検索するための LogicMonitor API キー。 ポータル監視の詳細については、次を参照してください。 LogicMonitorポータルモニタリング.有り
ホスト名.ソースNetScan で使用されるホスト名のソースを選択できます。 これは、既存のリソースに競合が見つかった場合に、重複したデバイスの作成を防ぐのに役立ちます。 詳細については、「」を参照してください。 NetScan のトラブルシューティング.いいえ
スキップ.device.dedupeデバイスの重複排除チェックをスキップできるため、LogicMonitor API 認証情報が不要になります。いいえ
  1.  フィルタ セクションに、次のように入力します。 フィルタリングにより、NetScan が作成するサイトとデバイス タイプを制御できます。
プロパティ説明
ミスト.api.org.サイト.名含めるまたは除外するサイトのカンマ区切りの名前。 デフォルトでは (このフィルタなし)、NetScan はすべてのサイトをリソース グループとしてインポートします。 スペースを含むサイト名には、スペースの前にバックスラッシュを含める必要があります。 例えば: Site\ For\ APs, SiteD, Site\ 23
ミスト.デバイス.タイプ操作設定に応じて、NetScan が含めたり除外したりするデバイス タイプのカンマ区切りの名前。 デフォルトでは (このフィルタなし)、NetScan はすべてのデバイス タイプをインポートします。 有効なデバイス タイプは次のとおりです。 apスイッチゲートウェイ.
  1. 拡張スクリプト Netscan を構成する場合は、「埋め込み Groovy スクリプト」を使用し、次のスクリプトを使用します。

警告: スクリプトを編集しないでください。編集された拡張スクリプト NetScan はサポートされていません。 LogicMonitor が提供するスクリプトを編集した場合、問題が発生した場合、LogicMonitor サポートは (独自の裁量により) サポートされているスクリプトで編集内容を上書きするよう要求する場合があります。

/*******************************************************************************
 * © 2007-2024 - LogicMonitor, Inc. All rights reserved.
 ******************************************************************************/
 
import com.logicmonitor.common.sse.utils.GroovyScriptHelper as GSH
import com.logicmonitor.mod.Snippets
import com.santaba.agent.util.Settings
import com.santaba.agent.AgentVersion
import groovy.json.JsonSlurper
import java.text.DecimalFormat

// To run in debug mode, set to true
Boolean debug = false
// To enable logging, set to true
Boolean log = false

// Set props object based on whether or not we are running inside a netscan or debug console
def props
try {
    hostProps.get("system.hostname")
    props = hostProps
    debug = true  // set debug to true so that we can ensure we do not print sensitive properties
}
catch (MissingPropertyException) {
    props = netscanProps
}

String organization = props.get("mist.api.org")
String token = props.get("mist.api.key")
if (!organization) {
    throw new Exception("Must provide mist.api.org to run this script.  Verify necessary credentials have been provided in Netscan properties.")
}
if (!token) {
    throw new Exception("Must provide mist.api.key credentials to run this script.  Verify necessary credentials have been provided in Netscan properties.")
}

def logCacheContext = "${organization}::juniper-mist"
Boolean skipDeviceDedupe = props.get("skip.device.dedupe", "false").toBoolean()
String hostnameSource    = props.get("hostname.source", "")?.toLowerCase()?.trim()

Integer collectorVersion = AgentVersion.AGENT_VERSION.toInteger()

// Bail out early if we don't have the correct minimum collector version to ensure netscan runs properly
if (collectorVersion < 32400) {
    def formattedVer = new DecimalFormat("00.000").format(collectorVersion / 1000)
    throw new Exception("Upgrade collector running netscan to 32.400 or higher to run full featured enhanced netscan. Currently running version ${formattedVer}.")
}

def modLoader = GSH.getInstance()._getScript("Snippets", Snippets.getLoader()).withBinding(getBinding())
def emit = modLoader.load("lm.emit", "0")
def lmDebugSnip = modLoader.load("lm.debug", "1")
def lmDebug     = lmDebugSnip.debugSnippetFactory(out, debug, log, logCacheContext)
def httpSnip    = modLoader.load("proto.http", "0")
def http        = httpSnip.httpSnippetFactory(props)
def cacheSnip   = modLoader.load("lm.cache", "0")
def cache       = cacheSnip.cacheSnippetFactory(lmDebug, logCacheContext)
// Only initialize lmApi snippet class if customer has not opted out
def lmApi
if (!skipDeviceDedupe) {
    def lmApiSnippet = modLoader.load("lm.api", "0")
    lmApi = lmApiSnippet.lmApiSnippetFactory(props, http, lmDebug)
}
def juniperMistSnip = modLoader.load("juniper.mist", "0")
def juniperMist     = juniperMistSnip.juniperMistSnippetFactory(props, lmDebug, cache, http)

String url = props.get("mist.api.url")?.trim() ?: "https://api.mist.com/api/v1/"
if (!url.endsWith("/")) url += "/"

String organizationDisplayname = props.get("mist.api.org.name")?.trim() ?: "MistOrganization"
String organizationFolder = props.get("mist.api.org.folder")?.trim() ? props.get("mist.api.org.folder") + "/" : ""
def sitesWhitelist = props.get("mist.api.org.sites")?.tokenize(",")?.collect{ it.trim() }
def collectorSitesCSV = props.get("mist.api.org.collector.sites.csv")
def collectorSiteInfo
if (collectorSitesCSV) {
    collectorSiteInfo = processCollectorSiteInfoCSV(collectorSitesCSV)
}

Map headers = ["Authorization":"token ${token}", "Accept":"application/json"]

List<Map> resources = []

def organizationSites = juniperMist.http.rawGet("${url}orgs/${organization}/sites", headers)
if (organizationSites) {
    organizationSites = juniperMist.slurper.parseText(organizationSites.content.text)
    organizationSites.each { organizationSite ->
        def siteName = organizationSite.get("name")
        if (sitesWhitelist != null && !sitesWhitelist.contains(siteName)) return    
        def site = organizationSite.get("id") 
        def siteDeviceStats = juniperMist.http.rawGet("${url}sites/${site}/stats/devices?type=all", headers)
        if (siteDeviceStats) {
            siteDeviceStats = juniperMist.slurper.parseText(siteDeviceStats.content.text)
            siteDeviceStats.each { siteDeviceStat ->
                def ip = siteDeviceStat.get("ip")
                def name = siteDeviceStat.get("name")
                def type = siteDeviceStat.get("type")
                def deviceProps = ["mist.api.org": organization, "mist.api.site": site, "mist.device.type": type, "mist.api.org.site.name": siteName, "mist.api.key": token]
                if (sitesWhitelist != null) deviceProps.put("mist.api.org.sites", props.get("mist.api.org.sites"))
                if (type == "ap") {
                    deviceProps.put("system.categories", "JuniperMistAP,NoPing")
                } else if (type == "switch") {
                    deviceProps.put("system.categories", "JuniperMistSwitch")
                } else if (type == "gateway") {
                    deviceProps.put("system.categories", "JuniperMistGateway")
                    if (siteDeviceStat.module_stat && siteDeviceStat.module2_stat) {
                        def primaryNodeIndex = siteDeviceStat.module_stat.node_name.get(0)
                        def secondaryNodeIndex = siteDeviceStat.module2_stat.node_name.get(0)
                        if (collectorSiteInfo) {
                            def collectorIdEntry = collectorSiteInfo.find{ it.contains(siteName) }
                            def collectorId = collectorIdEntry[0]
                            def folder = collectorIdEntry[2]                      
                            Map resource = [
                                "hostname"    : "${ip}-${secondaryNodeIndex}",
                                "displayname" : "${name}-${secondaryNodeIndex}",
                                "hostProps"   : deviceProps,
                                "groupName"   : ["${organizationFolder}${folder}/${siteName}"],
                                "collectorId" : collectorId
                            ]
                            resources.add(resource)
                        } else {
                            Map resource = [
                                "hostname"    : "${ip}-${secondaryNodeIndex}",
                                "displayname" : "${name}-${secondaryNodeIndex}",
                                "hostProps"   : deviceProps,
                                "groupName"   : ["${organizationFolder}${organizationDisplayname}/${siteName}"]
                            ]
                            resources.add(resource)
                        }
                        name = "${name}-${primaryNodeIndex}"
                    }
                }  
                if (ip && name && type && siteName) {
                    if (ip.contains("127.0.0.1")) ip = name
                    if (collectorSiteInfo) {
                        def collectorIdEntry = collectorSiteInfo.find{ it.contains(siteName) }
                        def collectorId = collectorIdEntry[0]
                        def folder = collectorIdEntry[2]                      
                        Map resource = [
                            "hostname"    : ip,
                            "displayname" : name,
                            "hostProps"   : deviceProps,
                            "groupName"   : ["${organizationFolder}${folder}/${siteName}"],
                            "collectorId" : collectorId
                        ]
                        resources.add(resource)
                    } else {
                        Map resource = [
                            "hostname"    : ip,
                            "displayname" : name,
                            "hostProps"   : deviceProps,
                            "groupName"   : ["${organizationFolder}${organizationDisplayname}/${siteName}"]
                        ]
                        resources.add(resource)
                    }
                }
            }
        } else {
            throw new Exception("Error occurred during sites/${site}/stats/devices?type=all HTTP GET: ${siteDeviceStats}.")
        }
    }

    emit.resource(resources)
} else {
    throw new Exception("Error occurred during orgs/${organization}/sites HTTP GET: ${organizationSites}.")
}

return 0


// Helper function to process a collector id, site organization device name, folder, and site CSV
def processCollectorSiteInfoCSV(String filename) {
    // Ensure relative filepath is complete with extension type
    def filepath
    if (!filename.contains("./")) {
        filepath = "./${filename}"
    }
    if (!filename.contains(".csv")) {
        filepath = "${filename}.csv"
    }

    // Read file into memory and split into list of lists
    def csv = new File(filepath)
    def rows = csv.readLines()*.split(",")
    def data

    // Verify whether headers are present and expected values
    // Sanitize for casing and extra whitespaces while gathering headers
    def maybeHeaders = rows[0]*.toLowerCase()*.trim()
    if (maybeHeaders.contains("collector id") && maybeHeaders.contains("site organization device name") && maybeHeaders.contains("folder") && maybeHeaders.contains("site")) {
        // Remove headers from dataset
        data = rows[1..-1]
    }
    // Bail out early if we don't have the expected headers in the provided CSV
    else {
        throw new Exception(" Required headers not provided in CSV.  Please provide \"Collector ID\", \"Site Organization Device Name\", \"Folder\", and \"Site\" (case insensitive).  Headers provided: \"${rows[0]}\"")
    }

    return data
}

Juniper Mist リソースの手動追加

  1. Juniper Mist Organization デバイス グループを作成します。 詳細については、次を参照してください。 デバイスグループの追加.
プロパティ
ミスト.api.org霧の組織ID
  1. デバイスを Mist Organization デバイス グループに追加します。 サイトデバイスグループ 以下のプロパティを追加します。詳細については、を参照してください。 組織 ID とサイト ID を見つけるにはどうすればよいですか?
プロパティ
ミスト.api.サイトミストサイトID
ミスト.api.キーAPIキー

ジュニパーミストの特性

ジュニパー ミストの追加の属性と値。

プロキシ設定

このスイートのモジュールは、プロキシサーバーを使用したHTTP接続をサポートします。 これは、コレクター設定で構成できます。を参照してください。 HTTPプロキシで使用するためのコレクターの構成、または次のデバイスホストプロパティを使用します。 デバイスホストのプロパティは、プロキシ構成のコレクター設定よりも優先されます。

プロパティ
プロキシを有効にします(オプション) このスイートは、ユーザーが構成した HTTP 呼び出しのコレクター プロキシ設定を使用するように記述されています。 有効にするには、値を に設定してこのデバイス プロパティを追加します。 true。 に設定 false 構成されたコレクタ プロキシ設定の使用をオーバーライドし、プロキシなしで接続します。
プロキシ.ホスト(オプション) コレクターの構成とは異なるプロキシ ホストを構成して接続します。
プロキシポート(オプション) コレクターの構成とは異なるプロキシ ポートを構成して接続します。

ミスト サイトを LM Envision コレクターにマッピングする

コレクターIDサイト組織のデバイス名フォルダサイト
11地域東部サイト地域_東部NYC
11地域東部サイト地域_東部MIA
11地域東部サイト地域_東部CLT
11地域東部サイト地域_東部ATL
11地域東部サイト地域_東部BOS
11地域東部サイト地域_東部CHS
1地域西サイト地域_西部LAX
1地域西サイト地域_西部LAS
1地域西サイト地域_西部SEA

コレクタ ID、サイト組織のデバイス名、フォルダ、およびサイトのカンマ区切り値。

Collector ID,Site Organization Device Name,Folder,Sites
11,Region_East_Sites,Region_East,NYC
11,Region_East_Sites,Region_East,MIA
11,Region_East_Sites,Region_East,CLT
11,Region_East_Sites,Region_East,ATL
11,Region_East_Sites,Region_East,BOS
11,Region_East_Sites,Region_East,CHS
1,Region_West_Sites,Region_West,LAX
1,Region_West_Sites,Region_West,LAS
1,Region_West_Sites,Region_West,SEA

ジュニパーミストのトラブルシューティング

  • このスイートは、コレクター スクリプト キャッシュに依存して、Juniper Mist API からデータを継続的に取得して保存し、レート制限の制約を最小限に抑えます。詳細については、を参照してください。 コレクタースクリプトのキャッシュ。継続的なデータ収集は、 Juniper_Mist_API DataSource: API 応答をコレクター スクリプト キャッシュに書き込みます。 Juniper_Mist_API このパッケージ内の他のすべてのモジュールが正常に動作するには、DataSource が正常に実行されている必要があります。
  • オンボーディング中に、その後、このパッケージ内の追加の PropertySource に対して Active Discovery を手動で実行できます。 Juniper_Mist_API データの収集を開始して、監視とトポロジ マッピングを促進します。
  • データギャップが存在する場合は、確認してください Juniper_Mist_API 正常に機能しており、スクリプト キャッシュの正常性を LogicMonitor_Collector_ScriptCache 情報元。

注: データの取得に使用される API にはレート制限があります。 API が到達不能かどうか、またはモニタリングが API レート制限に達していないかどうかを確認するには、Mist Organization デバイスの Juniper_Mist_API を確認してください。

パッケージ内のLogicModules

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

表示名 説明
Juniper_Mist_Topologyトポロジーソースミスト オーグのトポロジ。 サイト、および管理対象デバイス。
ミスト AP ビーコンデータソースMist が管理する AP ビーコンの状態とパフォーマンス。
ミスト AP ヘルスデータソースJuniper Mist が管理するワイヤレス アクセス ポイントの正常性と可用性。
ミスト AP インターフェイスデータソースJuniper Mist で管理された AP インターフェイスのステータスとネットワークの送受信統計。
ミスト AP パフォーマンスデータソースJuniper Mist が管理するワイヤレス アクセス ポイントのパフォーマンス。
ミスト AP ラジオデータソースミストで管理された AP の無線電力と使用状況。
ミストAPIデータソース監視対象の Mist 組織と Mist API 接続の状態。
ミストスイッチの性能データソースMist マネージド スイッチのパフォーマンス。
ミストスイッチヘルスデータソースMist で管理されたスイッチの状態。
ミスト WAN エッジ パフォーマンスデータソースMist マネージド セッション スマート ルーターのパフォーマンス。
ミスト WAN エッジ ヘルスデータソースMist で管理されたセッション スマート ルーターの正常性。
addCategory_Juniper_Mist_Deviceプロパティソースジュニパーミストを追加Juniper Mist によって管理されるデバイスへの system.category データを収集するには、Juniper_Mist_Org DataSource (ウォッチドッグ) が必要です。
addCategory_Juniper_Mist_OrganizationプロパティソースJuniper Mist 組織のデータ収集を担当するデバイスに JuniperMistOrg system.category を追加します。
addERI_Juniper_Mist_DeviceプロパティソースJuniper Mist デバイスの MAC アドレス ERI とデバイス タイプ ERT を設定します。 データを収集するには、Juniper_Mist_Org DataSource (ウォッチドッグ) が必要です。
addERI_Juniper_Mist_OrganizationプロパティソースJuniper Mist 組織の UUID ERI とクラスター ERT を設定します。

このパッケージの DataSource によって追跡されるさまざまなメトリクスに静的なデータポイントのしきい値を設定する場合、LogicMonitor はテクノロジー所有者のベスト プラクティス KPI 推奨事項に従います。

おすすめ:必要に応じて、環境固有のニーズに合わせてこれらの事前定義されたしきい値を調整します。データポイントのしきい値の調整の詳細については、を参照してください。 データポイントの静的しきい値の調整.

記事上で