#!/usr/bin/env pmpython # # Copyright (c) 2012,2018-2019 Red Hat. # Copyright (c) 2008,2012 Aconex. All Rights Reserved. # Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # """ PCP lmsensors Performance Metrics Domain Agent """ # pylint: disable=bad-continuation,line-too-long,consider-using-dict-items # pylint: disable=too-few-public-methods,too-many-nested-blocks import json import subprocess import re import argparse import sys import os.path from pcp.pmda import PMDA, pmdaMetric from pcp.pmapi import pmUnits, pmContext as PCP import cpmapi as c_api sensorvalues = {} # lookup sensorname -> sensorvalue (temp/fan) sensornames = {} # lookup sensornumber -> sensorname basename = "lmsensors" def lmsensors_get(): ''' read sensor data ''' if args.inject: # we will inject sensor data from a file f = open(args.inject.name, args.inject.mode) output = f.read() else: # we will read real sensor data with open(os.devnull, 'w') as devnull: p = subprocess.Popen(["/usr/bin/sensors", "-j"], stdout=subprocess.PIPE, stderr=devnull) output = json.loads(re.sub("[0-9]_", "_", p.communicate()[0].decode("utf-8"))) if args.debug_value and args.debug_value >= 0: print("function lmsensors_get(), json object after removing redundant naming:\n", output) for lvl0 in output.keys(): if args.debug_value and args.debug_value == 1: print("level 0 keys:", output[lvl0].keys()) for lvl1 in output[lvl0].keys(): adapter = output[lvl0]["Adapter"].lower().replace(" ", "_") if lvl1 != "Adapter": for lvl2 in output[lvl0][lvl1]: if "_input" in lvl2: sensorname = (lvl0+"."+adapter+"."+lvl1.replace(".", ",")).lower().replace(" ", "_").replace('-', '_') sensorvalues[sensorname] = output[lvl0][lvl1][lvl2] if args.debug_value and args.debug_value == 2: print("final array:", sensorvalues) class LmsensorsPMDA(PMDA): ''' lmsensors performance metrics domain agent ''' def lmsensors_fetch_callback(self, cluster, item, inst): ''' Returns a list of value,status (single pair) for one metric ''' lmsensors_get() if cluster == 0: # sanity checking: sort out temperatures below -127. # some sensors report -128 in error, from time to time. if re.search(r'temp', sensornames[item]): if int(sensorvalues[sensornames[item]]) < -127: return None # sanity checking: sort out negative values from fans if re.search(r'fan', sensornames[item]): if int(sensorvalues[sensornames[item]]) < 0: return None # if we made it until here, plainly return the read value return [sensorvalues[sensornames[item]], 1] # return [42, 1] return [c_api.PM_ERR_PMID, 0] def __init__(self, name, domain): ''' Initialisation - register metrics, callbacks, drop privileges ''' PMDA.__init__(self, name, domain) self.connect_pmcd() sensorcounter = 0 for k in sensorvalues: keysplit = k.split(".") self.add_metric(basename + "." + keysplit[0] + "." + keysplit[2], # metric name pmdaMetric(self.pmid(0, sensorcounter), # ID c_api.PM_TYPE_FLOAT, c_api.PM_INDOM_NULL, c_api.PM_SEM_INSTANT, # type, indom, semantics pmUnits(0, 0, 0, 0, 0, 0)), # and units. 'sensor values from "sensors -u"', # short 'sensor values from ' + k) # long help sensornames[sensorcounter] = k sensorcounter += 1 self.set_fetch_callback(self.lmsensors_fetch_callback) self.set_user(PCP.pmGetConfig('PCP_USER')) if args.debug_value: print("debug from __init__:") for k in sensorvalues: print(" sensorvalues key", k, " : value ", sensorvalues[k]) for k in sensornames: print(" sensornames key", k, " : value ", sensornames[k]) # main parser = argparse.ArgumentParser() parser.add_argument("-i", "--inject", type=argparse.FileType('r'), help="inject data from file instead of using sensors") parser.add_argument("-d", "--debug", dest="debug_value", type=int, choices=[0, 1, 2], help="change debug level, 0 is default") args = parser.parse_args() # if args.inject: if not os.path.isfile('/usr/bin/sensors'): print("/usr/bin/sensors not found! Is lm_sensors installed?") sys.exit(1) lmsensors_get() if args.debug_value: for key in sensorvalues: print("dict sensorvalues: ", key, " : ", sensorvalues[key]) if __name__ == '__main__': LmsensorsPMDA('lmsensors', 74).run()