Arista Campus Switch Power Supply State
We recently discovered that Arista Campus switches are either just not populating the OID for Power Supply states, or are using a different one, so in my API first approach to monitoring I decided to utilize the Arista EOS API to grab the power supply data, below are the discovery and collection scripts along with some of the key field for a Data source.
You will notice I am using the Model number to identify the Arista campus switches using an if not statement "if ( !(model.startsWith("CCS-")))" which will drop all the DC switches out of the script.
As always appreciate any feedback and ways to improve on these things. Have a great day.
Note: This is obviously shared on a best efforts basis, but we are using this across all of our campus switches and it works great (We found 3 on top of the one we knew had a failed PSU that had issues).
Applies to: hasCategory("Arista")
Description:
This will check the state of the power supply and return the following.
1 = Ok
0 = Down
This replaces the Arista SNMP PSU as this returns a null value for the campus switches.
Discovery Script:
/*
Script Name: Campus Power Supply Discovery
*/
import com.santaba.agent.groovyapi.http.*;
import com.santaba.agent.util.Settings
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
// Gather host statistics
username = hostProps.get("ssh.user");
password = hostProps.get("ssh.pass");
host = hostProps.get("auto.network.names");
model = hostProps.get("auto.endpoint.model")
vendor = hostProps.get("auto.endpoint.manufacturer")
//Only need to discove the devices if the vendor is Arista Networks
if ( !(vendor = "Arista Networks"))
{
println "Do not need to discover as not an Arista Device"
return(0)
}
//Now we need to check if the model is one of these specific models if it is then fine
if ( !(model.startsWith("CCS-")))
{
println "Not a Campus Switch"
return(0)
}
//Build Authentication JSON to send to switch
def authJson = JsonOutput.toJson([username:username,password:password]);
//Build URL
url = "https://"+host+"/login";
// Make the call
httpClient = Client.open(host, 443);
def response = httpClient.post(url, authJson,["Content-Type":"application/json"]);
if ( !(httpClient.getStatusCode() =~ /200/))
{
println "Failed to retrieve data "+httpClient.getStatusCode
return(1)
}
//Get Session data so we can extract the session string
String sessionData = httpClient.getHeader("Set-Cookie");
sessionData.substring(sessionData.lastIndexOf("Session=")+1,sessionData.length());
// Remove everything including the ; after the semiColon in session Data
def firstPass = sessionData.split(';')[0];
// Remove everything before and including the = this will leave you with the session data.
def session = firstPass.split('=')[1];
// Now we can gather the data to do this we need to build the command JSON output, URL and Header
def GetStatus = JsonOutput.toJson([jsonrpc: "2.0",method: "runCmds",params: ["version": 1,cmds: [ "show environment power" ],format: "json"],"id": "1"])
def powerUrl = "https://"+host+"/command-api";
def powerHeader = ["Cookie":session,"Content-Type":"application/json"]
// Now we can retrieve the data.
//httpClient = Client.open (host,443)
def powerData = httpClient.post(powerUrl, GetStatus ,powerHeader);
if ( !(httpClient.getStatusCode() =~ /200/))
{
println "Failed to retrieve data "+httpClient.getStatusCode
return 1
}
String powerContent = httpClient.getResponseBody()
def powerTable = new JsonSlurper().parseText(powerContent)
def encoded_instance_props_array = []
def wildvalue = ""
def wildalias = ""
def description = ""
//println powerTable
powerTable.result[0].powerSupplies.each { psuNo,powerSupply ->
wildvalue = "Power_Supply_"+psuNo
wildalias = "${wildvalue}:${powerSupply.modelName}"
description = "${wildvalue}/${powerSupply.modelName}"
def instance_props = [
"auto.power_suppLy": "Power Supply " + psuNo,
"auto.power_model_name": powerSupply.modelName
]
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("&")}"
}
return 0Collection Script:
/*
Script Name: Campus Power Supply Collection
*/
import com.santaba.agent.groovyapi.http.*;
import com.santaba.agent.util.Settings
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
// Gather host statistics
username = hostProps.get("ssh.user");
password = hostProps.get("ssh.pass");
host = hostProps.get("auto.network.names");
model = hostProps.get("auto.endpoint.model")
vendor = hostProps.get("auto.endpoint.manufacturer")
//Only need to discove the devices if the vendor is Arista Networks
if ( !(vendor = "Arista Networks"))
{
println "Do not need to discover as not an Arista Device"
return(0)
}
//Now we need to check if the model is one of these specific models if it is then fine
if ( !(model.startsWith("CCS-")))
{
println "Not a Campus Switch"
return(0)
}
//Build Authentication JSON to send to switch
def authJson = JsonOutput.toJson([username:username,password:password]);
//Build URL
url = "https://"+host+"/login";
// Make the call
httpClient = Client.open(host, 443);
def response = httpClient.post(url, authJson,["Content-Type":"application/json"]);
if ( !(httpClient.getStatusCode() =~ /200/))
{
println "Failed to retrieve data "+httpClient.getStatusCode
return(1)
}
//Get Session data so we can extract the session string
String sessionData = httpClient.getHeader("Set-Cookie");
sessionData.substring(sessionData.lastIndexOf("Session=")+1,sessionData.length());
// Remove everything including the ; after the semiColon in session Data
def firstPass = sessionData.split(';')[0];
// Remove everything before and including the = this will leave you with the session data.
def session = firstPass.split('=')[1];
// Now we can gather the data to do this we need to build the command JSON output, URL and Header
def GetStatus = JsonOutput.toJson([jsonrpc: "2.0",method: "runCmds",params: ["version": 1,cmds: [ "show environment power" ],format: "json"],"id": "1"])
def powerUrl = "https://"+host+"/command-api";
def powerHeader = ["Cookie":session,"Content-Type":"application/json"]
// Now we can retrieve the data.
//httpClient = Client.open (host,443)
def powerData = httpClient.post(powerUrl, GetStatus ,powerHeader);
if ( !(httpClient.getStatusCode() =~ /200/))
{
println "Failed to retrieve data "+httpClient.getStatusCode
return 1
}
String powerContent = httpClient.getResponseBody()
def powerTable = new JsonSlurper().parseText(powerContent)
def encoded_instance_props_array = []
def wildvalue = ""
def wildalias = ""
def description = ""
powerTable.result[0].powerSupplies.each { psuNo,powerSupply ->
wildvalue = "Power_Supply_"+psuNo
wildalias = "Power_Supply_"+psuNo+":${powerSupply.modelName}"
psuRawState = "${powerSupply.state}"
if (psuRawState == "ok") {
psuState = 1
}
else {
psuState = 0
}
println "${wildvalue}.psuState=${psuState}"
}
return 0
Joe Williams
·11 months agoLooks good, but I do have a question. Why not include the model part in the applies to? That would prevent the wasted cpu cycles on the collector?
SteveBamford
OP11 months agoThe main reason was that we will ultimately have a mixture of 24 and 48 port models that we will be supporting so rather than have to put each specific model in, which we would then need to maintain, it was simpler to say anything "CCS" (Campus Switches) would work.
Joe Williams
·11 months agoI understand that part but not why you wouldn't just put it in the appliesto?
SteveBamford
OP11 months agoAh ok sorry misunderstood, good suggestion will make the changes to the script.
SteveBamford
OP11 months agoWell the data source, but you hopefully knew what I meant. 🙂
SteveBamford
OP11 months agoThanks for this implemented successfully without issue and definitely something I will remember going forward. Really useful and something I overlooked.