Skip to content

Instantly share code, notes, and snippets.

@davelee212
Created July 5, 2025 19:51
Show Gist options
  • Select an option

  • Save davelee212/a3db0add871d9c0fe06fca7bc914ca0e to your computer and use it in GitHub Desktop.

Select an option

Save davelee212/a3db0add871d9c0fe06fca7bc914ca0e to your computer and use it in GitHub Desktop.
import groovy.json.JsonSlurper
import java.time.LocalDateTime
import com.logicmonitor.mod.Snippets
// switch on to enable debug output
def debug = true
// get the info we need to call the API
def client_key = hostProps.get("ciscosupportapi.key")
def client_secret = hostProps.get("ciscosupportapi.pass")
def serial_number = hostProps.get("auto.endpoint.serial_number")
// Get an API token. This calls a function that will get it from collector cache if available, otherwise will call the API to generate a new token
api_token = getToken(client_key, client_secret, false, debug)
// Call the Product Information API to get basic information about the device
def apiURL = new URL("https://apix.cisco.com/product/v1/information/serial_numbers/${serial_number}");
connection = apiURL.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("Authorization", "Bearer " + api_token);
if (connection.responseCode == 200) {
apiResponse = connection.inputStream.withReader { Reader reader -> reader.text }
} else {
println("Failed: ${connection.responseCode}")
}
apiResponseJson = new JsonSlurper().parseText(apiResponse);
println "serial_number=${serial_number}"
def base_pid = apiResponseJson.product_list[0].base_pid
println "base_pid=${base_pid}"
def product_name = apiResponseJson.product_list[0].product_name
println "product_name=${product_name}"
def product_type = apiResponseJson.product_list[0].product_type
println "product_type=${product_type}"
def product_series = apiResponseJson.product_list[0].product_series
println "product_series=${product_series}"
def product_category = apiResponseJson.product_list[0].product_category
println "product_category=${product_category}"
def product_subcategory = apiResponseJson.product_list[0].product_subcategory
println "product_subcategory=${product_subcategory}"
def release_date = apiResponseJson.product_list[0].release_date
println "release_date=${release_date}"
// Call the EOX API to get end-of-life information about the device (if it is available)
def eoxApiURL = new URL("https://apix.cisco.com/supporttools/eox/rest/5/EOXBySerialNumber/1/${serial_number}");
connection = eoxApiURL.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("Authorization", "Bearer " + api_token);
if (connection.responseCode == 200) {
apiResponse = connection.inputStream.withReader { Reader reader -> reader.text }
} else {
println("Failed: ${connection.responseCode}")
}
apiResponseJson = new JsonSlurper().parseText(apiResponse);
// Cisco: Last date to receive service and support for the product. After this date, all support services for the product are unavailable, and the product becomes obsolete.
if (apiResponseJson.EOXRecord[0].LastDateOfSupport) {
println "auto.support.endofsupport=${apiResponseJson.EOXRecord[0].LastDateOfSupport.value}"
}
// Cisco: Last date that Cisco Engineering might release any software maintenance releases or bug fixes to the software product. After this date, Cisco Engineering no longer develops, repairs, maintains, or tests the product software.
if (apiResponseJson.EOXRecord[0].EndOfSWMaintenanceReleases ) {
println "auto.support.endofgeneralupdates=${apiResponseJson.EOXRecord[0].EndOfSWMaintenanceReleases.value}"
}
// Cisco: Last date that Cisco Engineering may release a planned maintenance release or scheduled software remedy for a security vulnerability issue.
if (apiResponseJson.EOXRecord[0].EndOfSecurityVulSupportDate) {
println "auto.support.endofsecurityupdates=${apiResponseJson.EOXRecord[0].EndOfSecurityVulSupportDate.value}"
}
// Cisco: URL to the EoX product bulletin associated with the product.
if (apiResponseJson.EOXRecord[0].LinkToProductBulletinURL) {
println "auto.support.eolfurtherinfo=${apiResponseJson.EOXRecord[0].LinkToProductBulletinURL.value}"
}
// Coverage API
// Create GET request
def coverageApiURL = new URL("https://apix.cisco.com/sn2info/v2/coverage/summary/serial_numbers/${serial_number}");
connection = coverageApiURL.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("Authorization", "Bearer " + api_token);
if (connection.responseCode == 200) {
apiResponse = connection.inputStream.withReader { Reader reader -> reader.text }
} else {
println("Failed: ${connection.responseCode}")
}
apiResponseJson = new JsonSlurper().parseText(apiResponse);
// println "auto.support.service_contract_cover=${apiResponseJson.serial_numbers[0].is_covered}"
// println "auto.support.warranty_end_date=${apiResponseJson.serial_numbers[0].warranty_end_date}"
// STANDARD OUTPUTS AVAILABLE FOR ALL DEVICES
// ==========================================
// Cisco: Indicates whether the specified serial number is covered by a service contract; one of the following values: YES or NO. If the serial number is covered by a service contract, the value is Yes.
def is_covered = apiResponseJson.serial_numbers[0].is_covered
if (is_covered) { println "auto.support.has_service_contract=${is_covered}" }
// Cisco: End date of the warranty for the specified serial number in the following format: YYYY-MM-DD; for example, 2010-01-01.
def warranty_end_date = apiResponseJson.serial_numbers[0].warranty_end_date
if (warranty_end_date) { println "auto.support.warranty_end_date=${warranty_end_date}" }
// THE FOLLOWING ARE ONLY AVAILABLE IF THE API USER HAS ACCESS TO CUSTOMERS SUPPORT CONTRACTS
// ==========================================================================================
// Cisco: Warranty service type; for example, WARR-3YR-HW-90D-SW.
def warranty_type = apiResponseJson.serial_numbers[0].warranty_type
if (warranty_type) { println "auto.support.warranty_type=${warranty_type}" }
// Cisco: Link to the description of the warranty type.
def warranty_type_description = apiResponseJson.serial_numbers[0].warranty_type_description
if (warranty_type_description) { println "auto.support.warranty_type_description=${warranty_type_description}" }
// Cisco: Service contract number; for example, 1234567, 2345678, 3456789.
def service_contract_number = apiResponseJson.serial_numbers[0].service_contract_number
if (service_contract_number) { println "auto.support.service_contract_number=${service_contract_number}" }
// Cisco: Description of the service type; for example, SMARTnet Premium 24x7x4.
def service_line_description = apiResponseJson.serial_numbers[0].service_line_description
if (service_line_description) { println "auto.support.service_line_description=${service_line_description}" }
// Cisco: Customer name associated to the contract install site; for example, CISCO SYSTEMS, INC..
def contract_site_customer_name = apiResponseJson.serial_numbers[0].contract_site_customer_name
if (contract_site_customer_name) { println "auto.support.contract_site_customer_name=${contract_site_customer_name}" }
// Function for retriving token from the collector cache or getting a new one from the Cisco API if we don't
// have one cached (either it's expired or we've never run this script before on this collector)
def getToken (client_key, client_secret, force = false, debug = false) {
// Do we already have a token in the cache on this collector?
def scriptCache = this.class.classLoader.loadClass("com.santaba.agent.util.script.ScriptCache").getCache();
access_token = scriptCache.get("cisco-support-api-token") ?: null
if (access_token == null || force == true) {
// we must create a new token as there wasn't a valid one in the cache, or the
// calling script has forced us to get a new one
LMDebugPrint("Getting a new token from Cisco API", debug)
// Create POST URL.
def loginUrl = new URL("https://id.cisco.com/oauth2/default/v1/token");
connection = loginUrl.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setDoOutput(true);
// Build credential check
def authRequest = 'grant_type=client_credentials&client_id=' + client_key + '&client_secret=' + client_secret
// Write credential request to output stream.
def writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(authRequest);
writer.flush();
response = connection.inputStream.withReader { Reader reader -> reader.text }
jsonResponse = new JsonSlurper().parseText(response);
// calculate the datetime that the token will expire and add it to the json response
LocalDateTime now = LocalDateTime.now();
LocalDateTime expiryDateTime = now.plusSeconds(jsonResponse.expires_in)
jsonResponse.expiryDateTime = expiryDateTime
// store the token in the cache with a lifetime 2 mins less than what it really has to make sure
// we don't try and use it when it is about to expire
cacheLifetime = (jsonResponse.expires_in - 120) * 1000
scriptCache.set("cisco-support-api-token", jsonResponse.access_token, cacheLifetime)
access_token = jsonResponse.access_token
} else {
LMDebugPrint("Reusing token from collector cache", debug)
}
return access_token
}
/**
* Helper function to print out debug messages for troubleshooting purposes.
*/
def LMDebugPrint(message, boolean debug) {
if (debug) {
println(message.toString())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment