Versa SD-WAN モニタリング
最終更新日: 11 年 2024 月 XNUMX 日LogicMonitor は、Versa SDWAN アプライアンスのすぐに使用できる監視機能を提供します。組織の健全性、サイト、サイトによって生成されるトラフィック、Versa SDWAN アプライアンスを監視するように設計されており、Versa Director API を使用してサイト デバイスの統計情報とデータを取得します。
要件
- コレクターバージョン 32.400 以上
- Versa Director ポータルまたは Versa Director API を使用する API ユーザーとパスワード。
監視にリソースを追加する
NetScan を実行して Versa SDWAN リソースを追加するか、手動でリソースを追加することができます。NetScan を実行することをお勧めします。NetScan は、各 Versa 組織サイトのデバイス グループの下にデバイスを作成します。
詳細については、を参照してください。 ネットスキャンとは.
高度な NetScan を使用して Versa SD-WAN リソースを追加する
Advanced NetScan の使用の詳細については、次を参照してください。 強化されたスクリプト ネットスキャン.
1.あなたの中で ロジックモニターポータル > モジュール > 応募者と、Versa SD-WAN LogicModules をインストールします。
2。 案内する 「リソース」 > 「追加」 > 「複数のデバイス」 > 「高度な NetScan」.
この 高度な NetScan を追加する ページが表示されます。
3. この NetScan に関連付ける名前を入力します。たとえば、「Versa SD-WAN」などです。
4. NetScan を実行するコレクターを選択します。
デフォルトでは、NetScan は NetScan を実行しているコレクタに新しいリソースを割り当てます。
5。 選択 強化されたスクリプト NetScan 方法 ドロップダウンリスト。
6. 拡張スクリプトセクションで、 デバイスの資格情報 > このスキャンにカスタム資格情報を使用する.
7. NetScan に必要な Versa API 資格情報を提供し、NetScan がリソースを作成および整理する方法と場所を変更する次のプロパティを追加します。
プロパティ | 値 | 必須 |
ヴァーサ・ディレクター | Versa Director のホスト名。 | はい |
versa.ユーザー | Versa API ユーザー。NetScan はこのプロパティの値をマスクします。 | はい |
versa.pass | Versa API パスワード。NetScan はこのプロパティの値をマスクします。 | はい |
versa.フォルダ | この NetScan が作成するか、または既に存在する場合に使用する LogicMonitor リソース グループの名前。値には、ネストされた子フォルダーを指定できます (例: フォルダー/フォルダー/フォルダー)。 詳細については、を参照してください。 デバイス グループの概要。 | いいえ |
versa.organization | Versa 組織名。これは、Versa SD-WAN のルート リソース グループの名前になります。または、versa.organization プロパティを使用して代替ルート フォルダーを指定する場合は、最上位の子リソース グループの名前になります。 | いいえ |
versa.sites | 含めるサイト ID をコンマで区切って指定します (他の ID は除外されます)。 | いいえ |
versa.collector.sites.csv | NetScan によって作成された新しいリソースは、NetScan を実行するコレクターに割り当てられます。このプロパティは、CSV ファイルを使用してデフォルトの動作をオーバーライドし、Versa サイトと LM コレクター名に基づいて、Versa アプライアンス デバイスを目的のコレクターに割り当てます。CSV ファイルは、NetScan を実行するコレクターに保存する必要があります。Linux: /usr/local/logicmonitor/agent/bin Windows: C:\Program Files\LogicMonitor\Agent\bin 詳細については、以下を参照してください。 LM Envision コレクターへのサイトのマッピング. | いいえ |
versa.port (オプション) | Versa Director の URL を形成するために使用されるポート。デフォルトのポートは 9182 です。 | いいえ |
versa.url (オプション) | API 呼び出しの代替 URL。デフォルトでは、versa.director および versa.port プロパティを使用した URL になります。 | いいえ |
lmaccess.idまたはlogicmonitor.access.id | LogicMonitor APIアクセスIDは、ポータルに追加する前にNetScanで重複リソースを検索します。ポータル監視の詳細については、以下を参照してください。 LogicMonitorポータルモニタリング. | はい |
lmaccess.keyまたはlogicmonitor.access.key | LogicMonitor APIアクセスIDは、ポータルに追加する前にNetScanで重複リソースを検索します。ポータル監視の詳細については、以下を参照してください。 LogicMonitorポータルモニタリング. | はい |
ホスト名.ソース | NetScan で使用されるホスト名のソースを選択できます。 これは、既存のリソースに競合が見つかった場合に、重複したデバイスの作成を防ぐのに役立ちます。 詳細については、「」を参照してください。 NetScan のトラブルシューティング. | いいえ |
8。 選択 Groovyスクリプトを埋め込む 次のスクリプトを埋め込みます。
警告: スクリプトを編集しないでください。 編集された拡張スクリプト NetScan はサポートされていません。 LogicMonitor が提供するスクリプトを編集した場合、問題が発生した場合、LogicMonitor サポートは (独自の裁量により) サポートされているスクリプトで編集内容を上書きするよう要求する場合があります。 拡張スクリプト NetScan は、LM Envision リソースの作成を 600 時間あたり 600 以下に制限します。 XNUMX を超えるリソースを作成するには、すべてのリソースが追加されるまで NetScan を XNUMX 時間ごとに繰り返すようにスケジュールします。
/*******************************************************************************
* © 2007-2024 - LogicMonitor, Inc. All rights reserved.
******************************************************************************/
import com.santaba.agent.groovy.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
// 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
}
def director = props.get("versa.director")
def user = props.get("versa.user")
def pass = props.get("versa.pass")
if (!director) {
throw new Exception("Must provide versa.director to run this script. Verify necessary credentials have been provided in Netscan properties.")
}
if (!user) {
throw new Exception("Must provide versa.user to run this script. Verify necessary credentials have been provided in Netscan properties.")
}
if (!pass) {
throw new Exception("Must provide versa.pass credentials to run this script. Verify necessary credentials have been provided in Netscan properties.")
}
def logCacheContext = "versa-sdwan"
Boolean skipDeviceDedupe = props.get("skip.device.dedupe", "false").toBoolean()
if (debug) skipDeviceDedupe = true
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(GroovySystem.version).getScript("Snippets", Snippets.getLoader()).withBinding(getBinding())
def emit = modLoader.load("lm.emit", "1.1")
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 versaSnip = modLoader.load("versa.sdwan", "0")
def versa = versaSnip.versaSnippetFactory(props, lmDebug, cache, http)
String rootFolder = props.get("versa.folder", "Versa SD-WAN")
String url = props.get("versa.url")
def organization = props.get("versa.organization")
def sitesWhitelist = props.get("versa.sites")?.tokenize(",")?.collect{ it.trim() }
def collectorSitesCSV = props.get("versa.collector.sites.csv")
def collectorSitesInfo
if (collectorSitesCSV) collectorSitesInfo = processCollectorSiteInfoCSV(collectorSitesCSV)
// 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)
}
}
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 device names and display names, keyed by display name that would be assigned by the netscan, found within LogicMonitor portal. Refer to documentation for how to resolve name collisions using 'hostname.source' netscan property.",
"total" : 0,
"resources" : []
]
// Gather data from cache if running in debug otherwise make API requests
if (!organization) {
if (debug) {
organization = cache.cacheGet("${director}::organization")
if (organization) organization = versa.slurper.parseText(organization)?.find { it.name }?.name
} else {
organization = versa.http.rawGet(versa.url + "/nextgen/organization", versa.headers)?.content?.text
if (organization) organization = versa.slurper.parseText(organization)?.find { it.name }?.name
}
}
def assets
if (debug) {
assets = cache.cacheGet("${director}::assets")
if (assets) assets = versa.slurper.parseText(assets)
} else {
assets = versa.http.rawGet(versa.url + "/nextgen/inventory/assets/", versa.headers)?.content?.text
if (assets) assets = versa.slurper.parseText(assets)
}
def appliances
if (debug) {
appliances = cache.cacheGet("${director}::appliances")
if (appliances) appliances = versa.slurper.parseText(appliances)
} else {
appliances = versa.http.rawGet(versa.url + "/nextgen/appliance/status", versa.headers)?.content?.text
if (appliances) appliances = versa.slurper.parseText(appliances)
}
appliances.each { appliance ->
def ip = appliance.nodesStatusList.first().get("hostIP")
def uuid = appliance.get("applianceUUID")
def name = appliance.get("applianceName")
if (ip == "NOT-APPLICABLE") ip = name
String displayName = name
def asset = assets.find { it.name == name }
if (asset) {
def siteName = asset."site-name"
if (sitesWhitelist != null && !sitesWhitelist.contains(siteName)) return
// 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)
if (!deviceMatch) deviceMatch = lmApi.findPortalDeviceByName(ip, args)
} else if (pathFlag == "all") {
deviceMatch = lmApi.checkExistingDevices(displayName, lmDevices)
if (!deviceMatch) deviceMatch = lmApi.checkExistingDevicesByName(ip, lmDevices)
}
}
if (deviceMatch) {
// Log duplicates that would cause additional devices to be created; unless these entries are resolved, they will not be added to resources for netscan output
def collisionInfo = [
(displayName): [
"Netscan" : [
"hostname" : ip,
"displayName": displayName
],
"LM" : [
"hostname" : deviceMatch.name,
"collectorId": deviceMatch.currentCollectorId,
"displayName": deviceMatch.displayName
],
"Resolved": false
]
]
// If user specified to use LM hostname on display name match, update hostname variable accordingly
// and flag it as no longer a match since we have resolved the collision with user's input
if (hostnameSource == "lm" || hostnameSource == "logicmonitor") {
ip = deviceMatch.name
deviceMatch = false
collisionInfo[displayName]["Resolved"] = true
}
// If user specified to use netscan data for hostname, update the display name to make it unique
// and flag it as no longer a match since we have resolved the collision with user's input
else if (hostnameSource == "netscan") {
// Update the resolved status before we change the displayName
collisionInfo[displayName]["Resolved"] = true
displayName = "${displayName} - ${ip}"
deviceMatch = false
}
duplicateResources["resources"].add(collisionInfo)
}
// Verify we have minimum requirements for device creation
if (name) {
if (ip == "127.0.0.1") ip = name
def deviceProps = [
"versa.director" : director,
"versa.user" : user,
"versa.pass" : pass,
"system.categories" : "VersaAppliance",
"versa.organization": emit.sanitizePropertyValue(organization),
"versa.name" : emit.sanitizePropertyValue(name),
"versa.uuid" : emit.sanitizePropertyValue(uuid)
]
if (url) deviceProps.put("versa.url", url)
if (asset.location) deviceProps.put("location", emit.sanitizePropertyValue(asset.location))
if (asset.latitude) deviceProps.put("latitude", asset.latitude)
if (asset.longitude) deviceProps.put("longitude", asset.longitude)
if (asset."site-id") deviceProps.put("versa.site.id", asset."site-id")
if (sitesWhitelist != null) deviceProps.put("versa.sites", emit.sanitizePropertyValue(sitesWhitelist))
if (siteName) deviceProps.put("versa.site.name", emit.sanitizePropertyValue(siteName))
// Set group and collector ID based on user CSV inputs if provided
def collectorId = null
Map resource = [:]
if (collectorSitesInfo) {
collectorId = collectorSitesInfo[siteId]["collectorId"]
def folder = collectorSitesInfo[siteId]["folder"]
siteName = collectorSitesInfo[siteId]["site"]
resource = [
"hostname" : ip,
"displayname": name,
"hostProps" : deviceProps,
"groupName" : ["${rootFolder}/${folder}/${siteName}"],
"collectorId": collectorId
]
} else {
def groupName = organization ? ["${rootFolder}/${organization}/${siteName}"] : ["${rootFolder}/${siteName}"]
resource = [
"hostname" : ip,
"displayname": name,
"hostProps" : deviceProps,
"groupName" : groupName
]
}
// Only add the collectorId field to resource map if we found a collector ID above
if (collectorId) {
resource["collectorId"] = collectorId
duplicateResources["resources"][displayName]["Netscan"][0]["collectorId"] = collectorId
}
if (!deviceMatch) {
resources.add(resource)
}
}
}
}
lmDebug.LMDebugPrint("Duplicate Resources:")
duplicateResources.resources.each {
lmDebug.LMDebugPrint("\t${it}")
}
emit.resource(resources, debug)
return 0
/**
* Processes a CSV with headers collector id, folder, and site name
* @param filename String
* @return collectorInfo Map with site id as key and Map of additional attributes as value
*/
Map processCollectorSitesInfoCSV(String filename) {
// Read file into memory and split into list of lists
def csv = newFile(filename, "csv")
def rows = csv.readLines()*.split(",")
def collectorInfo = [:]
// 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("folder") && maybeHeaders.contains("site")) {
Map headerIndices = [:]
maybeHeaders.eachWithIndex{ val, i ->
headerIndices[val] = i
}
// Index values for headers to ensure we key the correct index regardless of order
def ni = headerIndices["site"]
def ci = headerIndices["collector id"]
def fi = headerIndices["folder"]
// Remove headers from dataset
def data = rows[1..-1]
// Build a map indexed by site for easy lookups later
data.each{ entry ->
collectorInfo[entry[ni]] = [
"collectorId" : entry[ci],
"folder" : entry[fi]
]
}
}
// 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\", \"Folder Name, \"and Site Name (case insensitive). Headers provided: \"${rows[0]}\"")
}
return collectorInfo
}
/**
* 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)
}
9. では スケジュール セクション、選択 このNetScanをスケジュールに従って実行する.
動的環境の場合、NetScan を XNUMX 時間ごとに実行するようにスケジュールできます。
ご注意: 後続の NetScan 実行では、Versa SD-WAN の変更に基づいてリソースまたはリソース グループが追加または移動されます。ただし、NetScan にはリソースを削除する機能はありません。
10。 選択 Save or 保存して実行.
リソースを手動で追加する
NetScan を実行した後、追加されたリソースの数、または NetScan がリソースを作成しない場合はエラー メッセージの履歴を確認します。
1. Versa SDWAN デバイス グループを作成します。
詳細については、を参照してください。 デバイスグループの追加.
プロパティ | 値 |
ヴァーサ・ディレクター | Versa Director ホスト名 |
versa.ユーザー | Versa API ユーザー。NetScan はこのプロパティの値をマスクします。 |
versa.pass | Versa API パスワード。NetScan はこのプロパティの値をマスクします。 |
versa.port (オプション) | versa.port (オプション) |
versa.url (オプション) | API 呼び出しの代替 URL。デフォルトでは、versa.director および versa.port プロパティを使用した URL になります。 |
2. デバイスを Versa SDWAN デバイス グループに追加します。
3. Versa SDWAN リソース グループの下のリソースに次のプロパティと versa.device.id を追加するか、設定されていることを確認します。
プロパティ | 値 |
versa.uuid | Versa SDWANアプライアンスUUID |
LogicModulesをインポートする
LogicMonitor パブリック リポジトリから、パッケージ内の LogicModules にリストされているすべての Versa SDWAN LogicModules をインポートします。これらの LogicModules がすでに存在する場合は、最新バージョンであることを確認してください。
LogicModules がインポートされたら、監視を開始するために必要なプロパティを設定するために addCategory_Versa_SDWAN_Appliance PropertySource を実行する必要があります。選択されたデバイスが Versa_SDWAN_API DataSource でデータの収集を正常に開始すると、すべてのデバイスのデータ収集が自動的に開始されます。
モジュールのインポートの詳細については、 LMエクスチェンジ.
トラブルシューティング
- このスイートは コレクタースクリプトキャッシュ レート制限の制約を最小限に抑えるために、Versa Director API からデータを継続的に取得して保存します。継続的なデータ収集は、API 応答をコレクター スクリプト キャッシュに書き込む Versa_SDWAN_API データ ソースを通じて、選択された Versa デバイス上で維持されます。このデバイスに適切なカテゴリを設定するには、最初に addCategory_Versa_SDWAN_Appliance PropertySource を実行する必要があります。このパッケージの他のすべてのモジュールを正常に実行するには、Versa_SDWAN_API データ ソースが正常に実行されている必要があります。
- オンボーディング中、監視とトポロジ マッピングを迅速化するために、Versa_SDWAN_API がデータの収集を開始した後、このパッケージ内の追加の PropertySources に対して Active Discovery を手動で実行することが必要になる場合があります。
- データ ギャップが見られる場合、Versa_SDWAN_API が正常に機能していることを確認し、LogicMonitor_Collector_ScriptCache データ ソースでスクリプト キャッシュの健全性をチェックします。
注: データの取得に使用される API にはレート制限があります。任意の Versa アプライアンスで Versa_SDWAN_API をチェックして、API が到達不能かどうか、またはモニタリングが API レート制限に達したかどうかを確認します。
NetScan のトラブルシューティング
このスイートの NetScan は、ポータル内の既存のデバイスを更新して、Versa API から取得した関連情報を追加できます。また、表示名は同じだが system.hostname の値が異なるという競合がある場合、NetScan がポータル内に重複したデバイスを作成する可能性もあります。デバイスが適切に更新され、重複したデバイスが作成されないようにするために、この NetScan は LogicMonitor の API を使用して既存のデバイスを照会し、検出された名前の競合を報告します。このファイルは、コレクター ログでアクセスできます。
コレクタ ログの取得の詳細については、「」を参照してください。 コレクターのログ – LogicMonitor へのログの送信.
このレポート内のデバイスは、NetScan がプロパティ hostname.source で構成されていない限り、NetScan 出力の一部として LogicMonitor に報告されません。このプロパティを使用すると、ユーザーは、NetScan 出力で使用されるホスト名のソースを選択することによって、検出された名前の競合を解決できます。考えられる 2 つのホスト名ソースは、次の値によって決まります。
- 「lm」または「logicmonitor」 名前が競合しているデバイスは、LogicMonitor の既存の system.hostname を使用して、ポータル内のデバイスが NetScan を使用して更新されるようにします。 この設定では新しいデバイスは作成されません。
- 「netscan」名前が競合するデバイスは、NetScanスクリプトで決定されたsystem.hostnameを維持し、報告された表示名を追加して更新します。一意であり、ポータルに追加できることを確認します。このオプションは、厳密な命名規則がなく、同じ表示名を持つデバイスが複数ある場合に役立ちます。
ご注意: NetScan は、system.hostname の値を更新できません。 NetScans は、表示名、カスタム プロパティ、およびグループ割り当てを更新できます。
パッケージ内のLogicModules
LogicMonitor の Versa パッケージは、次の LogicModules で構成されています。完全なカバレッジを得るには、次の LogicModules をすべて LogicMonitor プラットフォームにインポートしてください。
表示名 | 種類 | Description |
Versa API | データソース | Versa SDWAN Director API の使用状況を監視します。 |
Versa SDWAN トンネル | データソース | Versa SDWAN トポロジをマップします。 |
Versa SDWANアプライアンスの健全性 | データソース | Versa SDWAN アプライアンスの健全性を監視します。 |
Versa SDWANアプライアンスのパフォーマンス | データソース | Versa SDWAN アプライアンスのパフォーマンスを監視します。 |
Versa SDWANアプライアンスインターフェース | データソース | Versa SDWAN アプライアンスのインターフェースを監視します。 |
追加カテゴリ_Versa_SDWAN_アプライアンス | プロパティソース | Versa によって管理されるデバイスに VersaAppliance システム カテゴリとその他の自動プロパティを追加します。 |
ERI_Versa_SDWAN_アプライアンスを追加 | プロパティソース | Versa リソース用の Versa 固有の ERI を検出して追加します。 |
Versa SDWAN トポロジ | トポロジーソース | Versa SDWAN トポロジをマップします。 |
このパッケージの DataSource によって追跡されるさまざまなメトリクスに静的なデータポイントのしきい値を設定する場合、LogicMonitor はテクノロジー所有者のベスト プラクティス KPI 推奨事項に従います。
推奨事項: 必要に応じて、LogicMonitor では、環境固有のニーズに合わせてこれらの定義済みしきい値を調整することを推奨します。データポイントしきい値の調整の詳細については、「データポイントの静的しきい値の調整」を参照してください。