Aruba EdgeConnect SD-WAN

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

LogicMonitor の Aruba EdgeConnect SD-WAN 監視パッケージは、アプライアンスとオーケストレーター API を活用して、EdgeConnect OS (ECOS) アプライアンスを監視します。 これは、重要なアプライアンスの SD-WAN の健全性とパフォーマンスのメトリクスを監視し、警告するように設計されています。

Aruba EdgeConnect SD-WAN アプライアンスの詳細については、「 REST API監視の例 Aruba からのドキュメント。

互換性

2023 年 9.0 月の時点で、LogicMonitor の Aruba EdgeConnect SD-WAN パッケージはアプライアンス バージョン 9.3 ~ XNUMX と互換性があることが知られています。

要件

モニタリングにリソースを追加する

Aruba EdgeConnect SD-WAN リソースをモニタリングにオンボードするには、次の方法を使用できます。

  • (推奨) 高度な NetScan
    NetScan の詳細については、次を参照してください。 ネットスキャンとは.
  • リソースを手動で追加する

高度な NetScan を使用してリソースを追加する

  1. MFAデバイスに移動する  モジュール > 応募者と、Aruba EdgeConnect SD-WAN モジュールをインストールします。 モジュールのリストについては、「パッケージ内の LogicModules」を参照してください。
  2. MFAデバイスに移動する  リソース > Add > 複数のデバイス > 高度なネットスキャン.
      高度な NetScan を追加する ページが表示されます。
  3. この NetScan に関連付ける名前を入力します。 たとえば、「Aruba SD-WAN デバイス」です。
  4. NetScan を実行するコレクタを選択します。
    詳細については、を参照してください。 コレクターの割り当て in 強化されたスクリプト ネットスキャン.
  5. 選択 強化されたスクリプト NetScan   方法 ドロップダウンリスト。
  6. 「拡張スクリプト」セクションから、次を選択します。 デバイスの資格情報 > このスキャンにカスタム資格情報を使用する.
  7. NetScan に必要な Aruba EdgeConnect SD-WAN 認証情報を提供する次のプロパティを追加し、NetScan がリソースを作成および編成する方法と場所を変更します。
プロパティ必須
aruba.orchestrator.api.key読み取り専用権限を持つ Orchestrator API キー。 詳細については、「~」を参照してください。 API キーのドキュメント有り
aruba.orchestrator.hostオーケストレーターの IP または FQDN。 詳細については、「~」を参照してください。 オーケストレーター情報の検索有り
lmaccess.id 
or 
ロジックモニター.アクセス.id
ポータルにリソースを追加する前に NetScan で重複リソースを検索するための LogicMonitor API アクセス ID。 ポータル監視の詳細については、次を参照してください。 LogicMonitorポータルモニタリング.有り
lmaccess.key
or
ロジックモニター.アクセス.キー
ポータルにリソースを追加する前に NetScan で重複リソースを検索するための LogicMonitor API キー。 ポータル監視の詳細については、次を参照してください。 LogicMonitorポータルモニタリング.有り
aruba.sdwan.org.フォルダーこの NetScan が作成するか、すでに存在する場合は使用する LogicMonitor リソース グループの名前。 値は、ネストされた子フォルダー (フォルダー/フォルダー/フォルダーなど) にすることができます。これはデフォルトで「Aruba EdgeConnect SDWAN」になります。動的デバイス グループは NetScans によって追加されないため、これを動的デバイス グループに割り当てるべきではありません。 詳細については、「」を参照してください。 デバイスグループの概要いいえ
ホスト名.ソースNetScan で使用されるホスト名のソースを選択できます。 これは、既存のリソースに競合が見つかった場合に、重複したデバイスの作成を防ぐのに役立ちます。 詳細については、「NetScan のトラブルシューティング」を参照してください。いいえ
  1. 「Groovy スクリプトを埋め込む」を選択し、次のスクリプトを埋め込みます。

警告: スクリプトを編集しないでください。 編集された拡張スクリプト NetScan はサポートされていません。 LogicMonitor が提供するスクリプトを編集した場合、問題が発生した場合、LogicMonitor サポートはサポートされているスクリプトで編集内容を上書きするよう要求する場合があります。 拡張スクリプト NetScan は、LM Envision リソースの作成を 600 時間あたり 600 以下に制限します。 9 を超えるリソースを作成するには、すべてのリソースが追加されるまで NetScan を XNUMX 時間ごとに繰り返すようにスケジュールします。 XNUMX. 「スケジュール」セクションで、「スケジュールに従ってこの NetScan を実行する」を選択します。 動的環境の場合、NetScan を XNUMX 時間ごとに実行するようにスケジュールできます。

/*******************************************************************************
 * © 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.AgentVersion
import java.text.DecimalFormat
import groovy.json.JsonOutput
import groovy.json.JsonSlurper

// To run in debug mode, set to true
Boolean debug = false
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
}

// Required properties
def creds = props.get("aruba.orchestrator.api.key")
def host = props.get("aruba.orchestrator.host")

// Optional properties
def rootFolder = props.get("aruba.sdwan.org.folder") ?: "Aruba EdgeConnect SDWAN"
Boolean skipDeviceDedupe = props.get("skip.device.dedupe", "false").toBoolean()
String hostnameSource = props.get("hostname.source")?.toLowerCase()?.trim() ?: ""

// Retrieve the collector version
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 script netscan. Currently running version ${formattedVer}.")
}

if (!creds || !host) {
    throw new Exception("Must provide aruba.orchestrator.api.key and aruba.orchestrator.host to run this script.  Verify necessary fields have been provided in NetScan properties.")
}

// Load the snippets
def modLoader = GSH.getInstance()._getScript("Snippets", Snippets.getLoader()).withBinding(getBinding())
def lmEmit = modLoader.load("lm.emit", "1")
def lmDebug = modLoader.load("lm.debug", "1").debugSnippetFactory((PrintStream) out, debug, log, "aruba-sdwan")
def http = modLoader.load("proto.http", "0").httpSnippetFactory(props)
def cache = modLoader.load("lm.cache", "0").cacheSnippetFactory(lmDebug, "aruba-sdwan")
def arubaSnippet = modLoader.load("aruba.sdwan", "0").arubaSdwanFactory(props, lmDebug, cache, http)

// 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)
}

// CSV file containing headers "Site ID" and "Site Name" to customize group names created
// Save in /usr/local/logicmonitor/agent/bin directory (Linux)
//  or C:\Program Files\LogicMonitor\Agent\bin directory (Windows)
String csvFile = props.get("aruba.sdwan.sites.csv")

// Convert to map with site ID as key
Map siteInfo = null
if (csvFile) {
    siteInfo = processCSV(csvFile)
}

// Get information about devices that already exist in LM portal
List fields = ["name", "currentCollectorId", "displayName"]
Map args = ["size": 1000, "fields": fields.join(",")]
def lmDevices
// But first determine if the portal size is within a range that allows us to get all devices at once
def pathFlag, portalInfo, timeLimitSec, timeLimitMs
if (!skipDeviceDedupe) {
    portalInfo = lmApi.apiCallInfo("Devices", args)
    timeLimitSec = props.get("lmapi.timelimit.sec", "60").toInteger()
    timeLimitMs = (timeLimitSec) ? Math.min(Math.max(timeLimitSec, 30), 120) * 1000 : 60000 // Allow range 30-120 sec if configured; default to 60 sec

    if (portalInfo.timeEstimateMs > timeLimitMs) {
        lmDebug.LMDebugPrint("Estimate indicates LM API calls would take longer than time limit configured.  Proceeding with individual queries by display name for each device to add.")
        lmDebug.LMDebugPrint("\t${portalInfo}\n\tNOTE:  Time limit is set to ${timeLimitSec} seconds.  Adjust this limit by setting the property lmapi.timelimit.sec.  Max 120 seconds, min 30 seconds.")
        pathFlag = "ind"
    }
    else {
        lmDebug.LMDebugPrint("Response time indicates LM API calls will complete in a reasonable time range.  Proceeding to collect info on all devices to cross reference and prevent duplicate device creation.\n\t${portalInfo}")
        pathFlag = "all"
        lmDevices = lmApi.getPortalDevices(args)
    }
}
// Get your data and build your list of resources
List<Map> resources = []

def now = new Date()
def dateFormat = "yyyy-MM-dd'T'HH:mm:ss.s z"
TimeZone tz = TimeZone.getDefault()
Map duplicateResources = [
        "date"     : now.format(dateFormat, tz),
        "message"  : "Duplicate display names found within LogicMonitor portal wherein hostname in LM does not match hostname in Netscan output.  Refer to documentation for how to resolve name collisions using 'hostname.source' netscan property.",
        "total"    : 0,
        "resources": []
]


def appliancesData = arubaSnippet.httpGet("appliance")
def orchestratorInfo = arubaSnippet.httpGet("gmsserver/info")

appliancesData?.each { device ->
    String displayName = device.hostName
    def collectorId
    def ip = device.ip
    // Check for existing device in LM portal with this displayName; set to false initially and update to true when dupe found
    def deviceMatch = false
    // If customer has opted out of device deduplication checks, we skip the lookups where we determine if a match exists and proceed as false
    if (!skipDeviceDedupe) {
        if (pathFlag == "ind") {
            deviceMatch = lmApi.findPortalDevice(displayName, args)
        }
        else if (pathFlag == "all") {
            deviceMatch = lmApi.checkExistingDevices(displayName, lmDevices)
        }
    }

    if (deviceMatch) {
        if (ip != deviceMatch.name) {
            def collisionInfo = [
                    (displayName): [
                            "Netscan" : [
                                    "hostname": device.ip
                            ],
                            "LM"      : [
                                    "hostname"   : deviceMatch.name,
                                    "collectorId": deviceMatch.currentCollectorId
                            ],
                            "Resolved": false
                    ]
            ]
            if (hostnameSource == "lm" || hostnameSource == "logicmonitor") {
                ip = deviceMatch.name
                collectorId = deviceMatch.currentCollectorId
                deviceMatch = false
                collisionInfo[displayName]["Resolved"] = true
            }
            else if (hostnameSource == "netscan") {
                collisionInfo[displayName]["Resolved"] = true
                displayName = "${displayName} - ${ip}"
                deviceMatch = false
            }

            duplicateResources["resources"].add(collisionInfo)
        }
        else {
            deviceMatch = false
        }
    }

    def groupName
    def site = device.site
    if (siteInfo) {
        if (siteInfo[site]) {
            groupName = ["${rootFolder}/${siteInfo[site]["SiteFolder"]}"]
            if (siteInfo[site]["CollectorId"]) {
                collectorId = "${siteInfo[site]["CollectorId"]}"
            }
        }
    } else {
        groupName = device.site ? ["${rootFolder}/${device.site}"] : ["${rootFolder}"]
    }

    Map resource = [
            "hostname"   : device.ip,
            "displayname": device.hostName,
            "groupName"  : groupName,
            "hostProps"  : [
                    "aruba.orchestrator.host"            : orchestratorInfo?.host ?: orchestratorInfo.hostName,
                    "aruba.appliance.nepk"               : device.nePk,
                    "aruba.orchestrator.serial.number"   : orchestratorInfo?.serialNumber,
                    "aruba.orchestrator.model"           : orchestratorInfo?.model,
                    "aruba.orchestrator.software.version": orchestratorInfo?.release,
                    "aruba.orchestrator.host.name"       : orchestratorInfo?.hostName,
                    "aruba.orchestrator.platform"        : orchestratorInfo?.platform,
                    "aruba.orchestrator.os"              : orchestratorInfo?.osRev ?: orchestratorInfo?.release
            ]
    ]

    if (collectorId) {
        resource["collectorId"] = collectorId
        if (duplicateResources["resources"][displayName]["Netscan"][0]) {
            duplicateResources["resources"][displayName]["Netscan"][0]["collectorId"] = collectorId
        }
    }

    if (!deviceMatch) {
        resources.add(resource)
    }
}

// Output validated data in JSON format
lmEmit.resource(resources, debug)

// Report devices that already exist in LM via log file named after root folder
if (duplicateResources["resources"].size() > 0) {
    def netscanDupLog = new File("../logs/NetscanDuplicates/${rootFolder.replaceAll(" ", "_")}.json")
    new File(netscanDupLog.getParent()).mkdirs()
    duplicateResources["total"] = duplicateResources["resources"].size()
    def json = JsonOutput.prettyPrint(JsonOutput.toJson(duplicateResources))
    netscanDupLog.write(json)
    if (hostnameSource) {
        lmDebug.LMDebug("${duplicateResources["resources"].size()} devices found that were resolved with hostname.source=${hostnameSource} in netscan output.  See LogicMonitor/Agent/logs/NetscanDuplicates/${rootFolder.replaceAll(" ", "_")}.json for details.")
    } else {
        lmDebug.LMDebug("${duplicateResources["resources"].size()} devices found that were not reported in netscan output.  See LogicMonitor/Agent/logs/NetscanDuplicates/${rootFolder.replaceAll(" ", "_")}.json for details.")
    }
}

return 0

////////////////////////////////////////////////////////////// CSV PROCESSING METHODS ///////////////////////////////////////////////////////////
/**
 * Sanitizes filepath and instantiates File object
 * @param filename String
 * @param fileExtension String
 * @return File object using sanitized relative filepath
 */
File newFile(String filename, String fileExtension) {
    // Ensure relative filepath is complete with extension type
    def filepath
    if (!filename.startsWith("./")) {
        filepath = "./${filename}"
    }
    if (!filepath.endsWith(".${fileExtension}")) {
        filepath = "${filepath}.${fileExtension}"
    }

    return new File(filepath)
}

/**
 * Helper function to process CSV with site id and name info
 * @param String filename Filename of the CSV containing user-defined site info
 * @return Map siteInfo with site ID as the key and site name as the value
 */
Map processCSV(String filename) {
    File cacheFile = newFile(filename, "csv")
    def rows = cacheFile.readLines()*.split(",")

    def siteInfo = [:]

    // 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("site folder name") && maybeHeaders.contains("site name")) {
        Map headerIndices = [:]
        maybeHeaders.eachWithIndex { val, i ->
            headerIndices[val] = i
        }
        // Index values for headers to ensure we key the correct index regardless of order
        def sn = headerIndices["site name"]
        def colId = headerIndices["collector id"]
        def sf = headerIndices["site folder name"]

        // Remove headers from dataset
        data = rows[1..-1]
        // Build a map of common site names with site name as key
        data.each { entry ->
            siteInfo[entry[sn]] = [
                    "SiteFolder" : entry[sf],
                    "CollectorId": entry[colId]
            ]
        }
    }
    // Bail out early if we don't have the expected headers in the provided CSV, we can't properly associate Site IDs with common names without clear headers
    else {
        throw new Exception(" Required headers not provided in CSV.  Please provide \"Site Folder Name\" and \"Site Name\" (case insensitive).  Headers provided: \"${rows[0]}\"")
    }
    return siteInfo
}
///////////////////////////////////////////////////////////////////// END //////////////////////////////////////////////////////////////////////
  1. 選択 Save or 保存して実行.

NetScan を実行した後、追加されたリソースの数、または NetScan がリソースを作成しない場合はエラー メッセージの履歴を確認します。

リソースを手動で追加する

  1. Aruba EdgeConnect 組織デバイス グループを作成します。
    詳細については、を参照してください。 デバイスグループの追加.
  2. デバイスを Aruba Organization グループに追加します。
  3. 次のプロパティがリソース上または Aruba EdgeConnect 組織リソース グループの下に設定されていることを追加または確認します。
プロパティ
aruba.アプライアンス.ユーザー 
or 
Silverpeak.user
アプライアンスのユーザー名
詳細については、以下を参照してください アプライアンスの「ユーザー アカウント」タブ Aruba からのドキュメント。
aruba.アプライアンス.パス 
or 
Silverpeak.pass
アプライアンスのパスワード
詳細については、以下を参照してください アプライアンスの「ユーザー アカウント」タブ Aruba からのドキュメント。
システムのホスト名アプライアンスの IP または FQDN

プロパティの設定の詳細については、を参照してください。 リソースとインスタンスのプロパティ.

LogicModulesのインポート

LogicMonitor パブリックリポジトリから、すべての Aruba EdgeConnect SD-WAN LogicModule をインポートします。

これらの LogicModule がすでに存在する場合は、最新バージョンであることを確認してください。

LogicModule がインポートされると (以前のセットアップ要件がすべて満たされていると仮定して)、データ収集が自動的に開始されます。 モジュールのインポートの詳細については、を参照してください。 LMエクスチェンジ.

レガシーLogicModulesからの移行

これらのモジュールは、Aruba EdgeConnect SD-WAN デバイスを個別の LogicMonitor リソースとして監視し、Silver Peak (レガシー) モジュールへのインプレース アップグレードではありません。 詳細については、「」を参照してください。 シルバー ピーク モニタリング (レガシー).

推奨事項: これらのモジュールを Silver Peak (レガシー) モジュール (または他のサードパーティ監視ソリューション) と並行して使用して、同じ Aruba ネットワーク内の同じ Aruba EdgeConnect デバイスを監視しないでください。 そうすると、モジュールとサードパーティの監視ソリューションの両方でエラーやデータのギャップが発生する可能性があります。 リスクを軽減するには、組織の変更管理プロセスに従ってください。

トラブルシューティング

  • このパッケージは、コレクター スクリプト キャッシュに依存して、Aruba EdgeConnect API モジュールからデータを継続的に取得して保存し、レート制限の制約を最小限に抑えます。 詳細については、「」を参照してください。 コレクタースクリプトのキャッシュ。 データのギャップが発生した場合は確認してください Aruba_EdgeConnect_SDWAN_API が正常に実行されており、LogicMonitor_Collector_ScriptCache データソースでスクリプト キャッシュの状態を確認します。
  • このパッケージでは、API 呼び出しを行うために個々のアプライアンスにアクセスする必要があります。 401 エラーが発生した場合は、アプライアンスのユーザー名とパスワードを設定していることを確認してください。 オーケストレーターのユーザー名とパスワードを追加する必要はありません。 詳細については、「 アプライアンスの「ユーザー アカウント」タブ Aruba からのドキュメント。

パッケージ内のLogicModules

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

表示名タイプ説明
addCategory_ArubaEdgeConnectSDWANプロパティソースシステム カテゴリ ArubaEdgeConnectSDWANAppliance と、関連するデバイス情報を含む自動プロパティを追加します。
addERI_ArubaEdgeConnectSDWANプロパティソースAruba EdgeConnect SD-WAN リソースの ERI を検出して追加します。
Aruba_EdgeConnect_SDWAN_トポロジートポロジーソースAruba EdgeConnect SD-WAN トンネル トポロジをマップします。
EdgeConnect SDWAN APIデータソースすべてのアプライアンス レベルのキャッシュと API 呼び出しを処理します。
エッジコネクト SDWAN BGPデータソースアプライアンスの BGP ネイバーのステータスを監視します。
EdgeConnect SDWAN ディスクデータソースAruba EdgeConnect アプライアンスのディスクをアプライアンス レベルで監視します。
EdgeConnect SDWAN の健全性データソース各 SD-WAN アプライアンスの状態を監視します。
EdgeConnect SDWAN インターフェイスデータソースアプライアンスの WAN/LAN インターフェイスを監視します。
EdgeConnect SDWAN のパフォーマンスデータソースEdgeConnect SD-WAN アプライアンスのパフォーマンスを監視します。
EdgeConnect SDWAN トンネルデータソースAruba EdgeConnect SD-WAN アプライアンスのオーバーレイ トンネルを監視します。
EdgeConnect ネクストホップデータソースAruba Edge Connect SD-WAN アプライアンスの WAN ネクストホップを監視します。

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

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

記事上で