Forum Discussion

SteveBamford's avatar
SteveBamford
Icon for Neophyte rankNeophyte
3 months ago
Solved

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 0

Collection 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's avatar
    Joe_Williams
    3 months ago

    I understand that part but not why you wouldn't just put it in the appliesto?

    hasCategory("Arista") && startsWith(auto.endpoint.model,"CCS")

     

6 Replies

  • Looks 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's avatar
      SteveBamford
      Icon for Neophyte rankNeophyte

      The 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's avatar
        Joe_Williams
        Icon for Professor rankProfessor

        I understand that part but not why you wouldn't just put it in the appliesto?

        hasCategory("Arista") && startsWith(auto.endpoint.model,"CCS")