Recent Discussions
Adding Arista AP's to LogicMonitor
There was a previous request about this, and I have been working on this my self, so I thought I would share what I have delivered. Required Custom Parameters. The Discovery and collection scripts are expecting the following custom properties to be present for each device I have added these at the folder (in our case "Networks") so they cascade down. AristaWIFI.api.endpoint - This is the endpoint within CV-Cue under advanced setting for configuration and management API integrations. AristaWIFI.api.key - The API Key for CV-CUE AristaWIFI.api.token - The API Token for CV-CUE If these are not provided then the collector and discovery scripts will fail. NetScan: I had issues getting the netscan to work in Groovy so wrote a pyhton script to do this which links to Arista CloudVision and LogicMonitor, I have something in my backlog now to migrate this to groovy, the biggest challenge I have is that the HTTP DELETE call in Groovy is expecting data which is not needed for the delete call to close the session. This also uses the Python Core Library we use for all of our LogicMonitor integrations, so sharing is a tad difficult as I would have share the script and our Core Library. If people think this is worth While I would add it in the future. I set a system category of "AristaWifi" to easily identify Arista AP's for the collection and discovery scripts. Finally I also include the AP's ID on discovery as this is used to pull the specific AP from CV-CUE as the custom Property "CVcueId". What Metrics can be collected. Currently I am collecting CPU and Memory which I have created a Arista WIFI General Metrics Data source, and Arista WIFI SSID Metrics which is collecting the Associated Clients and the SSID State which is whether it is Enabled (1) or Disabled (0), I also have unknown (3) if the information can not be retrieved from the JSON. Arista Wifi General Metrics: This data source is configured to use Script as the collection source, below is the script. Note: The logout is commented out until I can result the http delete issue mentioned above. /******************************************************************************* * Arista WIFI Integration with CUE for discovery of the AP's ******************************************************************************/ import com.santaba.agent.groovyapi.http.* import com.santaba.agent.groovy.utils.GroovyScriptHelper as GSH import com.logicmonitor.mod.Snippets import com.santaba.agent.AgentVersion import java.text.DecimalFormat import com.santaba.agent.util.Settings import groovy.json.JsonOutput import groovy.json.JsonSlurper import groovy.json.JsonBuilder import java.util.concurrent.Executors import java.util.concurrent.TimeUnit // 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 key = props.get("AristaWIFI.api.key") String token = props.get("AristaWIFI.api.token") String AristaEndPoint = props.get("AristaWIFI.api.endpoint") //Get the Arista CV WIFI Node Node Id as discovered in the scanning script and submitted to the device.. String nodeId = props.get("CVcueId") String clientId = "logicmonitor" String wifiUrl = "https://"+AristaEndPoint+"/wifi/api/" if (!key) { throw new Exception("Must provide AristaWIFI.api.key to run this script. Verify necessary credentials have been provided in Netscan properties.") } if (!token) { throw new Exception("Must provide AristaWIFI.api.token credentials to run this script. Verify necessary credentials have been provided in Netscan properties.") } if (!clientId) { throw new Exception("Must provide AristaWIFI.api.clientId credentials to run this script. Verify necessary credentials have been provided in Netscan properties.") } //def logCacheContext = "${org}::arista-wifi-cloud" //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}.") } httpClient = HTTP.open(AristaEndPoint,443); httpClient.setHTTPProxy('[YOUR Proxy]',8080); // Log in to arista loginurl = "https://"+AristaEndPoint+"/wifi/api/session" payloadstring = '{"type":"apiKeycredentials","keyId":"'+key+'","keyValue":"'+token+'","timeout":129,"clientIdentifier": "'+clientId+'"}'; def payload = payloadstring; //println payload; def loginResponse = httpClient.post(loginurl,payload,["Content-Type":"application/json"]); if ( !(httpClient.getStatusCode() =~ /20/) ) { // Error has occured println "Authentication Failure"; println httpClient.getStatusCode(); println loginResponse; return(1); } String RawCookie = httpClient.getHeader("Set-Cookie") //Have Kept but as yet not needed will remove if not needed.. String httpResponseBody = httpClient.getResponseBody() //Retrieve the Cookie to use from the header. AristaCookie = RawCookie.split(';')[0] //Retrieve AP data. deviceURL = 'manageddevices/aps?startindex=0&pagesize=1000&locationid=0&nodeid=0&boxid='+nodeId SendUrl = wifiUrl+deviceURL def header = ["Content-Type":"application/json","Cookie":AristaCookie] String deviceResponse = httpClient.get(SendUrl,header) if ( !(httpClient.getStatusCode() =~ /200/)) { println "Failed to retrieve data "+httpClient.getStatusCode return 1 } String deviceBody = httpClient.getResponseBody() def deviceJson = new JsonSlurper().parseText(deviceBody) def healthStats = deviceJson.managedDevices.healthStats def wildvalue = "" Integer rawminCPU = healthStats[0].minCpuUtilization Integer minCpu = rawminCPU/100 Integer rawavgCPU = healthStats[0].avgCpuUtilization Integer avgCpu = rawavgCPU/100 Integer rawmaxCPU = healthStats[0].maxCpuUtilization Integer maxCpu = rawmaxCPU/100 Integer rawminMem = healthStats[0].minMemoryUtilization Integer minMem = rawminCPU/100 Integer rawAvgMem = healthStats[0].avgMemoryUtilization Integer avgMem = rawAvgMem/100 Integer rawmaxMem = healthStats[0].maxMemoryUtilization Integer maxMem = rawmaxCPU/100 println "${wildvalue}.mincpu=${minCpu}" println "${wildvalue}.avgcpu=${avgCpu}" println "${wildvalue}.maxcpu=${maxCpu}" println "${wildvalue}.minMem=${minMem}" println "${wildvalue}.avgMem=${avgMem}" println "${wildvalue}.maxMem=${maxMem}" // Commented out log out process for now as will need to revisit currently reducing Timeout to 5 minutes for the session. /* String cookieString = '"'+AristaCookie+'"' def logoutheaders = ["Content-Type":"application/json","Cookie":AristaCookie] println logoutheaders def logoutResponse = httpClient.delete(loginurl,"{}",logoutheaders) logoutResult = httpClient.getStatusCode() if ( !(httpClient.getStatusCode() =~ /20/) ) { //Error has occured println "Logout Failure"; println httpClient.getStatusCode(); println loginResponse; return(1); } println logoutResponse;*/ def LMDebugPrint(message) { if (debug) { println(message.toString()) } } return 0 Arista WIFI SSID Metrics: This will collect the number of associated clients by Band (IE 2.4ghz) and SSID I have the created graphs to aggregate the data together for total number of associated clients. Discovery Script: /******************************************************************************* * Arista WIFI Integration with CUE for discovery of the AP's ******************************************************************************/ import com.santaba.agent.groovyapi.http.* import com.santaba.agent.groovy.utils.GroovyScriptHelper as GSH import com.logicmonitor.mod.Snippets import com.santaba.agent.AgentVersion import java.text.DecimalFormat import com.santaba.agent.util.Settings import groovy.json.JsonOutput import groovy.json.JsonSlurper import groovy.json.JsonBuilder import java.util.concurrent.Executors import java.util.concurrent.TimeUnit // 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 key = props.get("AristaWIFI.api.key") String token = props.get("AristaWIFI.api.token") String AristaEndPoint = props.get("AristaWIFI.api.endpoint") //Get the Arista CV WIFI Node Node Id as discovered in the scanning script and submitted to the device.. String nodeId = props.get("CVcueId") String clientId = "logicmonitor" String wifiUrl = "https://"+AristaEndPoint+"/wifi/api/" if (!key) { throw new Exception("Must provide AristaWIFI.api.key to run this script. Verify necessary credentials have been provided in Netscan properties.") } if (!token) { throw new Exception("Must provide AristaWIFI.api.token credentials to run this script. Verify necessary credentials have been provided in Netscan properties.") } if (!clientId) { throw new Exception("Must provide AristaWIFI.api.clientId credentials to run this script. Verify necessary credentials have been provided in Netscan properties.") } //def logCacheContext = "${org}::arista-wifi-cloud" //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}.") } httpClient = HTTP.open(AristaEndPoint,443); httpClient.setHTTPProxy('[Your Proxy]',8080); // Log in to arista loginurl = "https://"+AristaEndPoint+"/wifi/api/session" payloadstring = '{"type":"apiKeycredentials","keyId":"'+key+'","keyValue":"'+token+'","timeout":129,"clientIdentifier": "'+clientId+'"}'; def payload = payloadstring; //println payload; def loginResponse = httpClient.post(loginurl,payload,["Content-Type":"application/json"]); if ( !(httpClient.getStatusCode() =~ /20/) ) { // Error has occured println "Authentication Failure"; println httpClient.getStatusCode(); println loginResponse; return(1); } String RawCookie = httpClient.getHeader("Set-Cookie") //Have Kept but as yet not needed will remove if not needed.. String httpResponseBody = httpClient.getResponseBody() //Retrieve the Cookie to use from the header. AristaCookie = RawCookie.split(';')[0] //Retrieve AP data. deviceURL = 'manageddevices/aps?startindex=0&pagesize=1000&locationid=0&nodeid=0&boxid='+nodeId SendUrl = wifiUrl+deviceURL def header = ["Content-Type":"application/json","Cookie":AristaCookie] String deviceResponse = httpClient.get(SendUrl,header) if ( !(httpClient.getStatusCode() =~ /200/)) { println "Failed to retrieve data "+httpClient.getStatusCode return 1 } String deviceBody = httpClient.getResponseBody() def encoded_instance_props_array = [] def deviceJson = new JsonSlurper().parseText(deviceBody) def wildvalue = "" def wildalias = "" def description = "" def getOperatingBand = "" def getSSID = "" def radios = deviceJson.managedDevices.radios radios[0].each { RadioEntry -> // Build out wireless entries. getOperatingBand = RadioEntry.operatingBand RadioEntry.wirelessInterfaces.each { ssidEntry -> getssid = ssidEntry.ssid description = ssidEntry.bssid wildvalue = getOperatingBand+"_"+getssid wildalias = wildvalue def instance_props = [ "auto.opertating.band": RadioEntry.operatingBand, "auto.ssid": ssidEntry.ssid, "auto.bssid":ssidEntry.bssid, "auto.ssid.profileId":ssidEntry.ssidProfileId ] encoded_instance_props_array = instance_props.collect() { property, value -> URLEncoder.encode(property.toString()) + "=" + URLEncoder.encode(value.toString()) } println "${wildvalue}##${wildalias}##${description}####${encoded_instance_props_array.join("&")}" } } // Commented out log out process for now as will need to revisit currently reducing Timeout to 5 minutes for the session. /* String cookieString = '"'+AristaCookie+'"' def logoutheaders = ["Content-Type":"application/json","Cookie":AristaCookie] println logoutheaders def logoutResponse = httpClient.delete(loginurl,"{}",logoutheaders) logoutResult = httpClient.getStatusCode() if ( !(httpClient.getStatusCode() =~ /20/) ) { //Error has occured println "Logout Failure"; println httpClient.getStatusCode(); println loginResponse; return(1); } println logoutResponse;*/ def LMDebugPrint(message) { if (debug) { println(message.toString()) } } return 0 Collection Script: /******************************************************************************* * Arista WIFI Integration with CUE for discovery of the AP's ******************************************************************************/ import com.santaba.agent.groovyapi.http.* import com.santaba.agent.groovy.utils.GroovyScriptHelper as GSH import com.logicmonitor.mod.Snippets import com.santaba.agent.AgentVersion import java.text.DecimalFormat import com.santaba.agent.util.Settings import groovy.json.JsonOutput import groovy.json.JsonSlurper import groovy.json.JsonBuilder import java.util.concurrent.Executors import java.util.concurrent.TimeUnit // 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 key = props.get("AristaWIFI.api.key") String token = props.get("AristaWIFI.api.token") String AristaEndPont = props.get("AristaWIFI.api.endpoint") //Get the Arista CV WIFI Node Node Id as discovered in the scanning script and submitted to the device.. String nodeId = props.get("CVcueId") String clientId = "logicmonitor" String wifiUrl = "https://"+AristaEndPont+"/wifi/api/" if (!key) { throw new Exception("Must provide AristaWIFI.api.key to run this script. Verify necessary credentials have been provided in Netscan properties.") } if (!token) { throw new Exception("Must provide AristaWIFI.api.token credentials to run this script. Verify necessary credentials have been provided in Netscan properties.") } if (!clientId) { throw new Exception("Must provide AristaWIFI.api.clientId credentials to run this script. Verify necessary credentials have been provided in Netscan properties.") } if (!AristaEndPont) { throw new Exception("Must provide AristaWIFI.api.endpoint to run this script. Verify necessary variable is within your LogicMonitor instance before continuing.") } //def logCacheContext = "${org}::arista-wifi-cloud" //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}.") } httpClient = HTTP.open(AristaEndPont,443); httpClient.setHTTPProxy('[Your Proxy]',8080); // Log in to arista loginurl = "https://"+AristaEndPont+"/wifi/api/session" payloadstring = '{"type":"apiKeycredentials","keyId":"'+key+'","keyValue":"'+token+'","timeout":129,"clientIdentifier": "'+clientId+'"}'; def payload = payloadstring; //println payload; def loginResponse = httpClient.post(loginurl,payload,["Content-Type":"application/json"]); if ( !(httpClient.getStatusCode() =~ /20/) ) { // Error has occured println "Authentication Failure"; println httpClient.getStatusCode(); println loginResponse; return(1); } String RawCookie = httpClient.getHeader("Set-Cookie") //Have Kept but as yet not needed will remove if not needed.. String httpResponseBody = httpClient.getResponseBody() //Retrieve the Cookie to use from the header. AristaCookie = RawCookie.split(';')[0] //Retrieve AP data. deviceURL = 'manageddevices/aps?startindex=0&pagesize=1000&locationid=0&nodeid=0&boxid='+nodeId SendUrl = wifiUrl+deviceURL def header = ["Content-Type":"application/json","Cookie":AristaCookie] String deviceResponse = httpClient.get(SendUrl,header) if ( !(httpClient.getStatusCode() =~ /200/)) { println "Failed to retrieve data "+httpClient.getStatusCode return 1 } String deviceBody = httpClient.getResponseBody() def encoded_instance_props_array = [] def deviceJson = new JsonSlurper().parseText(deviceBody) def wildvalue = "" def wildalias = "" def description = "" def getOperatingBand = "" def getSSID = "" def radios = deviceJson.managedDevices.radios def ssidActive = 3 radios[0].each { RadioEntry -> // Build out wireless entries. getOperatingBand = RadioEntry.operatingBand RadioEntry.wirelessInterfaces.each { ssidEntry -> getssid = ssidEntry.ssid description = ssidEntry.bssid wildvalue = getOperatingBand+"_"+getssid wildalias = wildvalue if (ssidEntry.active == true) { ssidActive = 1 } else { ssidActive = 0 } println "${wildvalue}.numAssocClients=${ssidEntry.numAssocClients}" println "${wildvalue}.active=${ssidActive}" } } // Commented out log out process for now as will need to revisit currently reducing Timeout to 5 minutes for the session. /* String cookieString = '"'+AristaCookie+'"' def logoutheaders = ["Content-Type":"application/json","Cookie":AristaCookie] println logoutheaders def logoutResponse = httpClient.delete(loginurl,"{}",logoutheaders) logoutResult = httpClient.getStatusCode() if ( !(httpClient.getStatusCode() =~ /20/) ) { //Error has occured println "Logout Failure"; println httpClient.getStatusCode(); println loginResponse; return(1); } println logoutResponse;*/ def LMDebugPrint(message) { if (debug) { println(message.toString()) } } return 0SteveBamford4 days agoNeophyte88Views0likes1CommentAd integrated Zone transfer monitoring
Hi We are Monitoring Domain controllers in LogicMonitor and the environment has AD integrated zones transfers for LDAP is there any way we can monitor these as the existing DNS- datasource doesnot meet our requirements as it has only non-AD integrated zone transfersvenkat5 days agoNeophyte114Views0likes0CommentsRename a collector?
I swore that in the old UIv3 you could rename a collector hostname. I dont mean the resource representation of the collector, when it monitors itself, I mean the actual name it has in the collector context. When I try to manage the collector on the collectors page, there is no option to change it. But we have a situation where we have to. Does this mean we need to rebuild and redeploy the collector to change it? The 2 collectors have similar collector names (collector hostnames), and while their respective resource names (for self-monitoring) have different displaynames etc, on the machines themselves, they have the same system.sysname. So this is causing some weird bug where alerts on either collector cause the alert to show on both. Kind of amusing. COLLECTOR "DEVICE NAME" /// RESOURCE DISPLAYNAME /// SYSTEM.SYSNAME ------------------------------------------------------------------- CORP\FF-FF01 /// FF-FF01.CompanyA.Com /// FF-FF01 WAN\FF-FF01 /// FF-FF01.CompanyB.Com /// FF-FF01 Because the sysnames are also the same (they sit in completely different networks) I think its confusing LogicMonitor, so I suspect the team that deploys there is going to have to honestly redo one of the collectors completely. But when fishing around in the UIv4 collectors page, I saw no way to change the "CORP\FF-FF01" or "WAN\FF-FF01" part. I think the sysname is going to force a complete redeploy on one, but its just weird I cant change the name.Lewis_Beard5 days agoProfessor63Views0likes0CommentsLM API Auth - Bearer or LMv1 Token
Hi all I've been using the Logic Monitor API for a while and tend to use the LMv1 token auth method. You have to calculate a base64 signature for each request, which is fine, I've written a function to handle that for me. But, given that Bearer tokens are available, I wonder if I'm just making this all a bit too difficult on myself 🤣 As I understand it, if the API call was intercepted somehow, exposing the signature calculated from an LMv1 token would be less problematic because it's not the token itself, it has a limited lifetime and is valid just for the endpoint that was being used on that API call. Am I thinking along the rights lines security wise, or should I just make my life a little easier and switch to using Bearer tokens? DaveDave_Lee9 days agoAdvisor305Views1like1CommentBMC Remedy Integration
Hi all I'm looking to do an ITSM integration with BMC Helix/Remedy, which isn't natively supported. It looks as though we can create a new incident by making a POST request to their API. But, if we want to do an update, it seems their API requires that you first query the API for an internal ID for the Incident, then make a second call with the update referring to that internal ID. Apparently this behaviour in the API cannot be altered. I don't see any way to achieve this in LogicMonitor. Has anyone successfully integrated LM and BMC Helix/Remedy? I think we will likely need to build something to sit between and receive the updates from LM and then call the Helix API. Interested in hearing what others may have done to achieve this. DaveDave_Lee9 days agoAdvisor281Views0likes3CommentsAPI v3: Alert ServiceNow field
Sarah_Terry​ The V4 API can view/modify the ServiceNow link. Please add this to APIv3 (or permit system integration access to APIv4)? { "alertExternalTicketUrl" : { "servicenowIncidentLinks" : { "INC0010101" : "https://acme.service-now.com/now/nav/ui/classic/params/target/incident.do%3Fsys_id%3D1234211bda7ad090a6c7feaac8915678" } } }David_Bond10 days agoProfessor318Views0likes3CommentsI'm getting a bit bored with this ....
Can you create a default collector escalation chain setting .....Andy_C10 days agoNeophyte293Views0likes1CommentLM / ServiceNow Integration
I'm working on some API commands for ServiceNow from LogicMonitor and am trying to see if there's a way to see further information from the return payload from ServiceNow when a ticket is generated via the integration. In particular, I'm trying to capture the sys_id field from ServiceNow so that I can use this to access the ticket in an escalation step using a custom HTTPS API command. I can see the payload includes sys_id in the integration logs, and indeed LogicMonitor uses it to generate the link to the ticket on the alert screens. Does anyone know if there's a token or such that can be used to access this info, or if there would be a way of storing it for access?Jason_Clemons11 days agoNeophyte71Views0likes2CommentsMeraki Security Appliance Tunnels
We monitor several large Meraki networks for customers, and we’ve recently switched to LogicMonitor’s newer Meraki monitoring method for a few of them. One challenge we're running into is with the Meraki Security Appliance Tunnel datasource. With the Hub(Mesh) configuration, each Meraki security appliance gets a tunnel datasource instance for both WAN1 and WAN2, even if only one WAN is in use. The issue: when a firewall at Location A goes down, it triggers an alert from the Cisco_Meraki_SecurityApplianceHealth datasource (which is expected). But in addition to that, we also receive multiple alerts: A tunnel alert for every tunnel on the device 2 tunnel alerts on each remote firewall in the mesh that has a tunnel to that location(wan1 & wan2) This results in a flood of alerts, even though it all stems from a single tunnel being offline. To cut down on the noise, I tried building a Service and adding all the tunnel instances to it. That helps, but the Service alert only says the service is out of compliance—it doesn’t tell me which tunnel is down. Has anyone come up with a better way to monitor Meraki tunnels using the newer integration, without generating excessive alerts when one device goes offline? I'd almost prefer some ORG level device like the legacy method has and put the tunnel connections there whether they are Site-to-Site or 3rd Party. When a tunnel goes down I don't need every FW in the environment alerting that the tunnel is down.Shack11 days agoAdvisor55Views0likes1Comment