#!/usr/bin/env python # Nimble Storage - NagiosXI Disk Space API Check Script v1.1 # Tristan Self # The script utilises the Nimble Storage API to provide some basic disk space usage monitoring. Although the Nimble Storage alerting system via Infosight is very good, we all know the warm fuzzy feeling of seeing a nice green service status in NagiosXI. The script only really needs to be scheduled to run once every 30 minutes or so. The script makes use of the Nimble Storage API, it is recommended to create a read-only account on the Nimble Storage array(s), this can be AD/LDAP or local. # Version History # 1.0 - 20/01/2020 - First Release # 1.1 - 20/01/2020 - Feature Added - Added the performance monitoring statistics for Free space, so NagiosXI can graph these metrics overtime. # 1.2 - 02/02/2020 - Feature Added - Added the performance monitoring for all the ouputs, so NagiosXI can graph these metrics overtime; thanks to "42bios" for the suggestion and code. import requests import sys import json from requests.packages.urllib3.exceptions import InsecureRequestWarning import argparse requests.packages.urllib3.disable_warnings(InsecureRequestWarning) ############################################################################################# # Argument Collection ############################################################################################# # Parse the arguments passed from the command line. parser = argparse.ArgumentParser() parser.add_argument('-e','--endpointurl',help='Endpoint URL (e.g. https://arrayname.domain.com:5392)',required=True) parser.add_argument('-u','--username',help='API Username',required=True) parser.add_argument('-p','--password',help='API Password (in single quotes!)',required=True) parser.add_argument('-w','--warning',help='Warning threshold for free space in TB)',required=True) parser.add_argument('-c','--critical',help='Critical threshold for free space in TB)',required=True) parser.add_argument('-q','--pool',help='Pool name to monitor, normally this will be called "default"',required=True) parser.add_argument('-d','--debugmode',help='Enable debug mode',action='store_true') # Assign each arguments to the relevant variables. arguments = vars(parser.parse_args()) strEndpointURL = arguments['endpointurl'] strAPIPassword = arguments['password'] strAPIUsername = arguments['username'] intCritical = int(arguments['critical']) intWarning = int(arguments['warning']) strPoolName = arguments['pool'] intDebugMode = arguments['debugmode'] ############################################################################################# # Initalise and Clean Variables ############################################################################################# strCheckOutputStatusText = "OK" strCheckOutputStatus = 0 strCheckOutputText = "" strCheckOutputPerfData = "" if intDebugMode: print print "DEBUG MODE" print print "Endpoint URL:\033[0;32;40m",strEndpointURL,"\033[0m" print print ################################################################################################ # API Authentication ################################################################################################ # Get the authentication token. try: objToken = requests.post(strEndpointURL+'/v1/tokens', data = json.dumps({'data' : {'password':strAPIPassword,'username':strAPIUsername}}),verify=False) except requests.exceptions.RequestException as e: if intDebugMode: print e # Build and print to the screen the check result. print "CRITICAL - Failed to connect! Check EndpointURL, username and password." strCheckOutputStatus = 2 # Return the status to the calling program. sys.exit(strCheckOutputStatus) # Get the JSON from the request response, then extract the session token for actually making a connection. objTokenJSON = json.dumps(objToken.json(),indent=2) objTokenDict = json.loads(objTokenJSON) strAPIToken = objTokenDict['data']['session_token'] strAPITokenDict = {'X-Auth-Token':strAPIToken} ################################################################################################# # Basic Array Information ################################################################################################# # Get the Array's basic information objArrayInfo = requests.get(strEndpointURL+'/v1/arrays/detail', headers = strAPITokenDict, verify=False) objArrayInfoJSON = json.dumps(objArrayInfo.json(),indent=2) objArrayInfoDict = json.loads(objArrayInfoJSON) strArrayFullName = objArrayInfoDict.get('data')[0]['full_name'] strArraySerialNo = objArrayInfoDict['data'][0]['serial'] strArrayVersion = objArrayInfoDict['data'][0]['version'] ################################################################################################# # Total Array Disk Space ################################################################################################# # Get the list of all the pools in the Nimble Storage array. objArrayPoolsInfo = requests.get(strEndpointURL+'/v1/pools', headers = strAPITokenDict, verify=False) objArrayPoolsInfoJSON = json.dumps(objArrayPoolsInfo.json(),indent=2) objArrayPoolsInfoDict = json.loads(objArrayPoolsInfoJSON) if intDebugMode == 1: # Print the raw JSON output for debugging print json.dumps(objArrayPoolsInfoDict, indent=2) # Get the total number of pools in the array. intstartRowPools = objArrayPoolsInfoDict['startRow'] intendRowPools = objArrayPoolsInfoDict['endRow'] # This variable lists the number of pools there are in the array. # Get the ID of each shelf in the array and then get the relevant metrics from the array or shelf. for i in range(intstartRowPools,intendRowPools,1): if intDebugMode == 1: print "Shelf ID:\033[0;33;40m", objArrayPoolsInfoDict['data'][i]['id'],"\033[0m" # Build a object with the JSON response in it. objArrayPoolsDetailInfo = requests.get(strEndpointURL+'/v1/pools/detail', headers = strAPITokenDict, verify=False) objArrayPoolsDetailInfoJSON = json.dumps(objArrayPoolsDetailInfo.json(),indent=2) objArrayPoolsDetailInfoDict = json.loads(objArrayPoolsDetailInfoJSON) # Dump the JSON to the screen if requested. if intDebugMode == 1: print json.dumps(objArrayPoolsDetailInfoDict, indent=2) # Check the name of the pool, if its not matching the user's input, skip to the pool on the array. if strPoolName == objArrayPoolsDetailInfoDict['data'][i]['full_name']: # Get all the values for the key information we need and convert to various formats. strPoolName = objArrayPoolsDetailInfoDict['data'][i]['full_name'] intPoolCapacity = int(objArrayPoolsDetailInfoDict['data'][i]['capacity'])/1024/1024/1024 intPoolCapacityTB = int(objArrayPoolsDetailInfoDict['data'][i]['capacity'])/1024/1024/1024/1024 intPoolUsage = int(objArrayPoolsDetailInfoDict['data'][i]['usage'])/1024/1024/1024 intPoolUsageTB = int(objArrayPoolsDetailInfoDict['data'][i]['usage'])/1024/1024/1024/1024 intPoolFreeSpace = int(objArrayPoolsDetailInfoDict['data'][i]['free_space'])/1024/1024/1024 intPoolFreeSpaceTB = int(objArrayPoolsDetailInfoDict['data'][i]['free_space'])/1024/1024/1024/1024 fltPoolCompRatio = round(objArrayPoolsDetailInfoDict['data'][i]['compression_ratio'],2) fltPoolSavingsRatio = round(objArrayPoolsDetailInfoDict['data'][i]['savings_ratio'],2) # Check if the free space is below the thresholds the user has inputted, if warning, return the warning state, if critical state. # Bit messy way to do it, but check if it is in warning, if it is but not at critical, return warning. Then check if critical if its over that then the return will be critical, otherwise its OK. if intPoolFreeSpaceTB < intWarning: # Set Warning strCheckOutputStatus = 1 strCheckOutputStatusText = "WARNING" if intPoolFreeSpaceTB < intCritical: # Set critical strCheckOutputStatus = 2 strCheckOutputStatusText = "CRITICAL" # Prepare the Performance Data String #strCheckOutputPerfData = "|capacity=",intPoolCapacityTB,";;","usage=x;x;x","free=x;x;x" #strCheckOutputPerfData = "| capacity="+str(intPoolCapacityTB)+"TB;; usage="+str(intPoolUsageTB)+"TB;; free="+str(intPoolFreeSpaceTB)+"TB;"+str(intWarning)+";"+str(intCritical)+";0;"+intPoolCapacityTB #strCheckOutputPerfData = "| free="+str(intPoolFreeSpaceTB)+"TB;"+str(intWarning)+";"+str(intCritical)+";0;"+str(intPoolCapacityTB) strCheckOutputPerfData = "| used="+str(intPoolUsageTB)+"TB; capacity="+str(intPoolCapacityTB)+"TB; free="+str(intPoolFreeSpaceTB)+"TB; CompRatio="+str(fltPoolCompRatio)+"X; SavingRatio="+str(fltPoolSavingsRatio)+"X" #################################################################################################### # Result #################################################################################################### # Performance Monitoring String if intDebugMode == 1: print "Performance Data: ",strCheckOutputPerfData # Build and print to the screen the check result. print "{} - {} {} pool '{}', Capacity:{}GB ({}TB), Usage:{}GB ({}TB), Free:{}GB ({}TB), CompressionRatio:{}X, SavingsRatio:{}X {}".format(strCheckOutputStatusText,strArrayFullName,strArraySerialNo,strPoolName,intPoolCapacity,intPoolCapacityTB,intPoolUsage,intPoolUsageTB,intPoolFreeSpace,intPoolFreeSpaceTB,fltPoolCompRatio,fltPoolSavingsRatio,strCheckOutputPerfData) if intDebugMode == 1: print "Return Code: ",strCheckOutputStatus # Return the status to the calling program. sys.exit(strCheckOutputStatus)