Good morning everyone. I've been searching for ways to monitor an IPSec tunnel in LM, but so far I've been unable to find any articles on how to do this. We have a Meraki security device. The Meraki out-of-the-box LM modules do not come with a way to monitor S2S. It would greatly help out our IT team if we could receive a notification on whether or not one of our tunnels is misbehaving in LM.
First question is whether or not you've found something in the Exchange that fits the bill. Someone may have already built and published something.
Second question is, "How would you do this manually today?" If the data exists today, how do you get at it? Is there a web UI? If so, is there a corresponding API endpoint? Is the device hosting that API already added to LogicMonitor? Can you think of a process to repeatedly obtain that data every few minutes? If so, the only thing that would remain would be to script it out in Groovy (or your language of choice) and add it as a scripted DataSource.
Good morning everyone. I've been searching for ways to monitor an IPSec tunnel in LM, but so far I've been unable to find any articles on how to do this. We have a Meraki security device. The Meraki out-of-the-box LM modules do not come with a way to monitor S2S. It would greatly help out our IT team if we could receive a notification on whether or not one of our tunnels is misbehaving in LM.
Hi,
I don’t think I have a unique challenge: I would like to refer to a LogicMonitor graph to check the health of an IPSEC VPN at the time of a reported connectivity issue. The only thing special about my case is that we use VMware NSX-T as our endpoint.
Thanks
Tunnel status, speed, transmit Bps, receive Bps, throughput Bps, Utilization Percentage, Packet Loss Percentage, Jitter, Latency, Mean Opinion Score
Any others?
I have not checked the API for NSX-T to know what is available, but yes, those are great metrics to track.
There is value to recording the “status” of both phase 1 and phase 2 separately. Sometimes, phase 1 will remain up while phase 2 goes down. This can indicate a lack of activity within the scope of that phase 2 rather than a broken link between the sites.
When I built this for NSX-V (unpublished DataSource named “Jenzabar_VMware_NSX_EdgeIPSEC”), the excerpt below created the instances for phase 1 and phase 2. Note the different naming convention as well as the populated properties.
edges.each { edge ->
def confURL = "https://${hostname}/api/4.0/edges/${edge.id}/ipsec/config"
def confResponse = getURL(confURL, slurper, auth, debug)
def statusCode2 = confResponse[1]
if (statusCode2 == 200) {
def confOutput = confResponse[0].sites.sites
confOutput.each { conf ->
LMDebugPrint("conf: \n" + JsonOutput.prettyPrint(JsonOutput.toJson(conf)), debug)
// Phase 1
println "${edge.id}_${conf.siteId}##${conf.name} (Phase 1)######"+
"auto.nsx.edge=${edge.name} [${edge.id}]"+
"&auto.nsx.edgeId=${edge.id}"+
"&auto.nsx.ipsec.localIp=${conf.localIp}"+
"&auto.nsx.ipsec.siteId=${conf.siteId}"+
"&auto.nsx.ipsec.peerIp=${conf.peerIp}"
// Phase 2
conf.localSubnets.subnets.each { local ->
conf.peerSubnets.subnets.each { peer ->
tunnelKey = "${conf.localIp}_${local}-${conf.peerIp}_${peer}"
println "${tunnelKey}##${conf.name} (${tunnelKey})######"+
"auto.nsx.edge=${edge.name} [${edge.id}]"+
"&auto.nsx.edgeId=${edge.id}"+
"&auto.nsx.ipsec.localIp=${conf.localIp}"+
"&auto.nsx.ipsec.siteId=${conf.siteId}"+
"&auto.nsx.ipsec.peerIp=${conf.peerIp}"
}
}
}
}
}
The API for NSX-V also included a failureMessage. I created an enumeration metric (is this a proper term?) for which I started to translate common failureMessage values into numeric values (see excerpt below).
failureMessage = 0
if (tunnel.containsKey("failureMessage") && tunnel.failureMessage.length()) {
switch (tunnel.failureMessage.toLowerCase()) {
case "received delete for ipsec-sa":
failureMessage = 3
break
case "unknown":
failureMessage = 2
break
default:
failureMessage = 1
}
}
println "${tunnelKey}.failureMessage="+failureMessage
Out of curiosity to see how smart or dumb AI is (and perhaps for a little fun), I asked https://chat.openai.com (ChatGPT) the following:
“Using Groovy 2.4, Write a multi-instance LogicMonitor DataSource for VMware NSX-T that exposes each IPsec tunnel as a discrete DataSource instance with the following datapoints: tunnel status, tunnel speed, tunnel transmit Bps, tunnel receive Bps, Tunnel throughput Bps, Tunnel Utilization Percentage, Tunnel Packet Loss Percentage, Tunnel Jitter, Tunnel Latency, Tunnel Mean Opinion Score”
This was the response:
Here's an example of a Groovy 2.4 script for a multi-instance LogicMonitor DataSource for VMware NSX-T that exposes each IPsec tunnel as a discrete DataSource instance with the specified datapoints:
import com.santaba.agent.groovyapi.datasources.*
import com.santaba.agent.groovyapi.execute.*
// Define the credentials to access the NSX-T API
def nsxHost = "nsx-t-hostname"
def nsxUsername = "username"
def nsxPassword = "password"
// Define the API endpoint to retrieve the IPsec tunnels
def endpoint = "/api/v1/ipsec-tunnel"
// Initialize the LogicMonitor DataSource
def ds = new BasicDataSource("NSX-T IPsec Tunnels")
// Set the custom properties for the DataSource
ds.setMultiInstance(true)
ds.addCustomProperty("nsxHost", nsxHost)
ds.addCustomProperty("nsxUsername", nsxUsername)
ds.addCustomProperty("nsxPassword", nsxPassword)
// Define the datapoints to retrieve for each IPsec tunnel
def datapoints = [
"status",
"speed",
"txBps",
"rxBps",
"throughputBps",
"utilizationPercent",
"packetLossPercent",
"jitter",
"latency",
"meanOpinionScore"
]
// Loop through each IPsec tunnel and create a DataSource instance
executeWithApi("nsxt", { api ->
def tunnels = api.get(endpoint)
tunnels.each { tunnel ->
def instanceName = "Tunnel " + tunnel.id
def instance = ds.addInstance(instanceName)
// Set the instance custom properties
instance.addCustomProperty("tunnelId", tunnel.id)
// Add the datapoints to the instance
datapoints.each { datapoint ->
instance.addDatapoint(new SimpleDatapoint(datapoint))
}
}
})
// Save the DataSource
ds.save()
LM requires one script for discovery and one for collection. However, this gets you close. The output format needs to be adjusted. It’s interesting that it knew about the santaba libraries but did not use hostProps.get() method calls.
Using Groovy 2.4, write the discovery and collection scripts for a multi-instance LogicMonitor DataSource for VMware NSX-T that exposes each IPsec tunnel as a discrete DataSource instance with the following datapoints: tunnel status, tunnel speed, tunnel transmit Bps, tunnel receive Bps, Tunnel throughput Bps, Tunnel Utilization Percentage, Tunnel Packet Loss Percentage, Tunnel Jitter, Tunnel Latency, Tunnel Mean Opinion Score.
Below is the response:
Here's an example of a Groovy 2.4 script for the discovery and collection of a multi-instance LogicMonitor DataSource for VMware NSX-T that exposes each IPsec tunnel as a discrete DataSource instance with the specified datapoints:
Discovery script:
import com.santaba.agent.groovyapi.datasources.*
import com.santaba.agent.groovyapi.execute.*
// Define the credentials to access the NSX-T API
def nsxHost = "${nsxHost}"
def nsxUsername = "${nsxUsername}"
def nsxPassword = "${nsxPassword}"
// Define the API endpoint to retrieve the IPsec tunnels
def endpoint = "/api/v1/ipsec-tunnel"
// Define the datapoints to retrieve for each IPsec tunnel
def datapoints = [
"status",
"speed",
"txBps",
"rxBps",
"throughputBps",
"utilizationPercent",
"packetLossPercent",
"jitter",
"latency",
"meanOpinionScore"
]
// Initialize the LogicMonitor DataSource
def ds = new BasicDataSource("NSX-T IPsec Tunnels")
// Set the custom properties for the DataSource
ds.setMultiInstance(true)
ds.addCustomProperty("nsxHost", nsxHost)
ds.addCustomProperty("nsxUsername", nsxUsername)
ds.addCustomProperty("nsxPassword", nsxPassword)
// Retrieve the list of IPsec tunnels and create a DataSource instance for each tunnel
executeWithApi("nsxt", { api ->
def tunnels = api.get(endpoint)
tunnels.each { tunnel ->
def instanceName = "Tunnel " + tunnel.id
def instance = ds.addInstance(instanceName)
// Set the instance custom properties
instance.addCustomProperty("tunnelId", tunnel.id)
// Add the datapoints to the instance
datapoints.each { datapoint ->
instance.addDatapoint(new SimpleDatapoint(datapoint))
}
}
})
// Save the DataSource
ds.save()
Collection Script:
import com.santaba.agent.groovyapi.datasources.*
import com.santaba.agent.groovyapi.execute.*
import com.santaba.agent.groovyapi.http.*
// Retrieve the custom properties for the DataSource
def nsxHost = "${nsxHost}"
def nsxUsername = "${nsxUsername}"
def nsxPassword = "${nsxPassword}"
// Retrieve the API endpoint for the specified IPsec tunnel
def getEndpoint = { tunnelId ->
"/api/v1/ipsec-tunnel/${tunnelId}"
}
// Retrieve the datapoint values for the specified IPsec tunnel
def getData = { tunnelId ->
def datapoints = [
"status",
"speed",
"txBps",
"rxBps",
"throughputBps",
"utilizationPercent",
"packetLossPercent",
"jitter",
"latency",
"meanOpinionScore"
]
def values = [:]
executeWithApi("nsxt", { api ->
def endpoint = getEndpoint(tunnelId)
def tunnel = api.get(endpoint)
datapoints.each { datapoint ->
values[datapoint] = tunnel[datapoint]
}
})
values
}
// Loop through each IPsec tunnel and collect its datapoints
executeWithApi("nsxt", { api ->
def tunnels = api.get("/api/v1/ipsec-tunnel")
tunnels.each { tunnel ->
def instanceName = "Tunnel " + tunnel.id
def instance = findDataSourceInstance(dsName, instanceName)
if (instance != null
Meh, the discovery script looks like it’s trying to create the datasource, not create the instance output required for the discovery.
The collection script seems incomplete.
Since the santaba libraries are not documented (except for self documentation), it would be difficult to know exactly what it’s trying to save with the ds.Save() statement.
Reply
Login to the community
No account yet? Create an account
Enter your username or e-mail address. We'll send you an e-mail with instructions to reset your password.