mirror of
https://github.com/prometheus/node_exporter.git
synced 2024-11-23 12:30:46 +01:00
StorCli text collector: fix pylint issues and handle StorCli not installed (#758)
* StorCli text collector: fix pylint issues and handle StorCli not installed * StorCli text collector: Add HELP and TYPE strings.
This commit is contained in:
parent
af4cf20b46
commit
a40f7e78da
@ -1,31 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Script to parse StorCLI's JSON output and expose
|
||||
MegaRAID health as Prometheus metrics.
|
||||
|
||||
# Script to parse StorCLI's JSON output and expose
|
||||
# MegaRAID health as Prometheus metrics.
|
||||
#
|
||||
# Tested against StorCLI 'Ver 1.14.12 Nov 25, 2014'.
|
||||
#
|
||||
# StorCLI reference manual:
|
||||
# http://docs.avagotech.com/docs/12352476
|
||||
#
|
||||
# Advanced Software Options (ASO) not exposed as metrics currently.
|
||||
#
|
||||
# JSON key abbreviations used by StorCLI are documented in the standard command
|
||||
# output, i.e. when you omit the trailing 'J' from the command.
|
||||
Tested against StorCLI 'Ver 1.14.12 Nov 25, 2014'.
|
||||
|
||||
StorCLI reference manual:
|
||||
http://docs.avagotech.com/docs/12352476
|
||||
|
||||
Advanced Software Options (ASO) not exposed as metrics currently.
|
||||
|
||||
JSON key abbreviations used by StorCLI are documented in the standard command
|
||||
output, i.e. when you omit the trailing 'J' from the command.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
DESCRIPTION = """Parses StorCLI's JSON output and exposes MegaRAID health as
|
||||
Prometheus metrics."""
|
||||
VERSION = '0.0.1'
|
||||
|
||||
METRIC_PREFIX = 'megaraid_'
|
||||
METRIC_CONTROLLER_LABELS = '{{controller="{}", model="{}"}}'
|
||||
|
||||
|
||||
def main(args):
|
||||
""" main """
|
||||
|
||||
# exporter variables
|
||||
metric_prefix = 'megaraid_'
|
||||
metric_controller_labels = '{{controller="{}", model="{}"}}'
|
||||
|
||||
data = json.loads(get_storcli_json(args.storcli_path))
|
||||
|
||||
# It appears that the data we need will always be present in the first
|
||||
@ -33,12 +39,14 @@ def main(args):
|
||||
status = data['Controllers'][0]
|
||||
|
||||
metrics = {
|
||||
'status_code': status['Command Status']['Status Code'],
|
||||
'controllers': status['Response Data']['Number of Controllers'],
|
||||
}
|
||||
'status_code': status['Command Status']['Status Code'],
|
||||
'controllers': status['Response Data']['Number of Controllers'],
|
||||
}
|
||||
|
||||
for name, value in metrics.iteritems():
|
||||
print("{}{} {}".format(METRIC_PREFIX, name, value))
|
||||
print('# HELP {}{} MegaRAID {}'.format(metric_prefix, name, name.replace('_', ' ')))
|
||||
print('# TYPE {}{} gauge'.format(metric_prefix, name))
|
||||
print("{}{} {}".format(metric_prefix, name, value))
|
||||
|
||||
controller_info = []
|
||||
controller_metrics = {}
|
||||
@ -52,50 +60,69 @@ def main(args):
|
||||
for controller in overview:
|
||||
controller_index = controller['Ctl']
|
||||
model = controller['Model']
|
||||
controller_info.append(METRIC_CONTROLLER_LABELS.format(controller_index, model))
|
||||
controller_info.append(metric_controller_labels.format(controller_index, model))
|
||||
|
||||
controller_metrics = {
|
||||
# FIXME: Parse dimmer switch options
|
||||
# 'dimmer_switch': controller['DS'],
|
||||
# FIXME: Parse dimmer switch options
|
||||
# 'dimmer_switch': controller['DS'],
|
||||
|
||||
'battery_backup_healthy': int(controller['BBU'] == 'Opt'),
|
||||
'degraded': int(controller['Hlth'] == 'Dgd'),
|
||||
'drive_groups': controller['DGs'],
|
||||
'emergency_hot_spare': int(controller['EHS'] == 'Y'),
|
||||
'failed': int(controller['Hlth'] == 'Fld'),
|
||||
'healthy': int(controller['Hlth'] == 'Opt'),
|
||||
'physical_drives': controller['PDs'],
|
||||
'ports': controller['Ports'],
|
||||
'scheduled_patrol_read': int(controller['sPR'] == 'On'),
|
||||
'virtual_drives': controller['VDs'],
|
||||
'battery_backup_healthy': int(controller['BBU'] == 'Opt'),
|
||||
'degraded': int(controller['Hlth'] == 'Dgd'),
|
||||
'drive_groups': controller['DGs'],
|
||||
'emergency_hot_spare': int(controller['EHS'] == 'Y'),
|
||||
'failed': int(controller['Hlth'] == 'Fld'),
|
||||
'healthy': int(controller['Hlth'] == 'Opt'),
|
||||
'physical_drives': controller['PDs'],
|
||||
'ports': controller['Ports'],
|
||||
'scheduled_patrol_read': int(controller['sPR'] == 'On'),
|
||||
'virtual_drives': controller['VDs'],
|
||||
|
||||
# Reverse StorCLI's logic to make metrics consistent
|
||||
'drive_groups_optimal': int(controller['DNOpt'] == 0),
|
||||
'virtual_drives_optimal': int(controller['VNOpt'] == 0),
|
||||
}
|
||||
# Reverse StorCLI's logic to make metrics consistent
|
||||
'drive_groups_optimal': int(controller['DNOpt'] == 0),
|
||||
'virtual_drives_optimal': int(controller['VNOpt'] == 0),
|
||||
}
|
||||
|
||||
for name, value in controller_metrics.iteritems():
|
||||
print('{}{}{{controller="{}"}} {}'.format(METRIC_PREFIX, name, controller_index, value))
|
||||
print('# HELP {}{} MegaRAID {}'.format(metric_prefix, name, name.replace('_', ' ')))
|
||||
print('# TYPE {}{} gauge'.format(metric_prefix, name))
|
||||
print('{}{}{{controller="{}"}} {}'.format(metric_prefix, name,
|
||||
controller_index, value))
|
||||
|
||||
if controller_info:
|
||||
print('# HELP {}{} MegaRAID controller info'.format(metric_prefix, 'controller_info'))
|
||||
print('# TYPE {}{} gauge'.format(metric_prefix, name))
|
||||
for labels in controller_info:
|
||||
print('{}{}{} {}'.format(METRIC_PREFIX, 'controller_info', labels, 1))
|
||||
print('{}{}{} {}'.format(metric_prefix, 'controller_info', labels, 1))
|
||||
|
||||
|
||||
def get_storcli_json(storcli_path):
|
||||
storcli_cmd = [storcli_path, 'show', 'all', 'J']
|
||||
proc = subprocess.Popen(storcli_cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
return proc.communicate()[0]
|
||||
"""Get storcli output in JSON format."""
|
||||
|
||||
# Check if storcli is installed
|
||||
if os.path.isfile(storcli_path) and os.access(storcli_path, os.X_OK):
|
||||
storcli_cmd = [storcli_path, 'show', 'all', 'J']
|
||||
proc = subprocess.Popen(storcli_cmd, shell=False,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
output_json = proc.communicate()[0]
|
||||
else:
|
||||
# Create an empty dummy-JSON where storcli not installed.
|
||||
dummy_json = {"Controllers":[{
|
||||
"Command Status": {"Status Code": 0, "Status": "Success",
|
||||
"Description": "None"},
|
||||
"Response Data": {"Number of Controllers": 0}}]}
|
||||
output_json = json.dumps(dummy_json)
|
||||
|
||||
return output_json
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description=DESCRIPTION,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument('--storcli_path',
|
||||
PARSER = argparse.ArgumentParser(description=DESCRIPTION,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
PARSER.add_argument('--storcli_path',
|
||||
default='/opt/MegaRAID/storcli/storcli64',
|
||||
help='path to StorCLi binary')
|
||||
parser.add_argument('--version',
|
||||
PARSER.add_argument('--version',
|
||||
action='version',
|
||||
version='%(prog)s {}'.format(VERSION))
|
||||
args = parser.parse_args()
|
||||
ARGS = PARSER.parse_args()
|
||||
|
||||
main(args)
|
||||
main(ARGS)
|
||||
|
Loading…
Reference in New Issue
Block a user