Created
July 5, 2025 19:51
-
-
Save davelee212/a3db0add871d9c0fe06fca7bc914ca0e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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