root/freeipmi_

Revision 15, 7.1 kB (checked in by ixs, 13 years ago)

initial package

  • Property svn:executable set to *
Line 
1 #!/usr/bin/python
2 #
3 #    Copyright (C) 2011  Andreas Thienemann <andreas@bawue.net>
4 #
5 #    This program is free software: you can redistribute it and/or modify
6 #    it under the terms of the GNU General Public License as published by
7 #    the Free Software Foundation, either version 3 of the License, or
8 #    (at your option) any later version.
9 #
10 #    This program is distributed in the hope that it will be useful,
11 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #    GNU General Public License for more details.
14 #
15 #    You should have received a copy of the GNU General Public License
16 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 #
18
19 """
20 =head1 NAME
21
22 freeipmi_ - Munin plugin to retreive temperature and fan speed measurements
23 from a local machine via IPMI.
24
25 =head1 APPLICABLE SYSTEMS
26
27 All machines with an IPMI capable baseboard management controller.
28
29 =head1 CONFIGURATION
30
31 On most supported systems this plugin works nearly out of the box as long as
32 both Python and the freeipmi binaries in a semi-recent version are installed.
33
34 If the machine works out of the box can be tested by calling bmc-info.
35 If there's text output, a bmc card was detected. If there's an entry for
36 "Sensor Device" visible in the "Additional Device Support" entry you're good.
37
38 If you get a "ipmi_cmd_get_device_id: driver timeout" message you have most
39 likely no bmc to query.
40
41 In certain cases however bmc-info will just seem to hang for quite some time.
42 In this case, autodetection does not work because the smbios table has
43 incorrect information. One system know to experience this problem is the
44 HP Proliant Microserver.
45
46 Adding env.freeipmi_args "--no-probing --driver-type=KCS --driver-address=0xca2 --register-spacing=1"
47 to the munin plugin configuration will make the plugin work.
48
49 Basic configuration for every system is that the plugin needs to be called as root.
50
51 Add the following to your /etc/munin/plugin-conf.d/freeipmi:
52
53  [freeipmi_*]
54  user root
55
56 =head1 INTERPRETATION
57
58 The plugin shows the temperature in Celsius or the fanspeed in rotations per minute.
59
60 =head1 MAGIC MARKERS
61
62   #%# family=contrib
63   #%# capabilities=autoconf suggest
64
65 =head1 VERSION
66
67 0.0.1
68
69 =head1 BUGS
70
71 Only local support for now. Remote could be hacked in via freeipmi_args for now.
72
73 =head1 AUTHOR
74
75 Andreas Thienemann <andreas@bawue.net>
76
77 =head1 LICENSE
78
79 GPLv3+
80
81 =cut
82 """
83
84 import subprocess
85 import sys
86 import os
87 import re
88 import pprint
89
90 # Parse some environment variables
91 if os.getenv("freeipmi_args") is not None:
92     freeipmi_args = " %s" % (os.getenv("freeipmi_args"))
93 else:
94     freeipmi_args = ""
95
96 # We are a wildcard plugin, figure out whether we are called for temp or fan
97 if sys.argv[0].split("_")[1] == "temp":
98     mode = "Temperature"
99 elif sys.argv[0].split("_")[1] == "fan":
100     mode = "Fan"
101 else:
102     mode = None
103
104 def whereis(prog):
105     """Check if prog can be found in the path and if yes, return the full pathname"""
106     prog = os.path.basename(prog)
107     for dir in os.getenv("PATH").split(":"):
108         for root, dirs, files in os.walk(dir):
109             if prog in files:
110                 return os.path.join(dir, prog)
111     return None
112
113 def normalize_sensor(name):
114     name = name.lower().replace("-","M").replace("+","P")
115     name = re.sub("[^a-z0-9A-Z]","_", name)
116     return name
117
118 # Code sniplet from Philipp Keller
119 # http://code.pui.ch/2007/02/19/set-timeout-for-a-shell-command-in-python/
120 def timeout_command(command, timeout):
121     """call shell-command and either return its output or kill it
122     if it doesn't normally exit within timeout seconds and return None"""
123     import subprocess, datetime, os, time, signal
124     start = datetime.datetime.now()
125     process = subprocess.Popen(command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
126     while process.poll() is None:
127         time.sleep(0.1)
128         now = datetime.datetime.now()
129         if (now - start).seconds> timeout:
130             os.kill(process.pid, signal.SIGKILL)
131             os.waitpid(-1, os.WNOHANG)
132             return None
133     return process.stdout.read()
134
135 def bmc_detect():
136     """Check whether there's a baseboard management controller we can query."""
137     if whereis("bmc-info") is None:
138         print "no (bmc-info not found in path. Please install FreeIPMI.)"
139         sys.exit(0)
140     else:
141         out = timeout_command("bmc-info%s" % (freeipmi_args), 2)
142         if out is not None and "[Sensor Device]" in out:
143             print "yes"
144             sys.exit(0)
145         else:
146             print "no (no supported bmc found)"
147             sys.exit(0)
148
149 def read_sensors():
150     """Return all sensor data as a dict"""
151     out = timeout_command("ipmi-sensors --verbose%s" % (freeipmi_args), 2)
152     sensors = dict()
153     sensor = dict()
154     sensor_id = None
155     for line in out.split("\n"):
156         if ":" in line:
157             k,v = line.split(": ")
158             if k == "Record ID":
159                 sensor = dict()
160                 sensor_id = int(v)
161                 sensor[k] = v
162             else:
163                 sensor[k] = v
164         else:
165             sensors[sensor_id] = sensor
166     return sensors
167
168 def print_config():
169     """Return configuration arguments for munin"""
170     print "graph_title FreeIPMI Sensors: %s" % (mode)
171     if mode == "Fan":
172         print "graph_vlabel RPM"
173         print "graph_info This graph shows the RPMs of the fans as reported by IPMI"
174     elif mode == "Temperature":
175         print "graph_vlabel Degrees C"
176         print "graph_info This graph shows the temperatures as reported by IPMI"
177     print "graph_category sensors"
178     sensors = read_sensors()
179
180     for id in sorted(sensors):
181         if sensors[id]["Group Name"] == mode:
182             label = normalize_sensor(sensors[id]["Sensor Name"])
183             for n in ["Normal Max.", "Normal Min.", "Sensor Reading", "Lower Critical Threshold", "Upper Critical Threshold", "Lower Non-Critical Threshold", "Upper Non-Critical Threshold"]:
184                 sensors[id][n] = sensors[id][n].replace("NA","")
185                 sensors[id][n] = sensors[id][n].split('.')[0]
186
187             print "%s.label %s" % (label, label)
188             print "%s.warning %s:%s" % (label, sensors[id]["Lower Non-Critical Threshold"], sensors[id]["Upper Non-Critical Threshold"])
189             print "%s.critical %s:%s" % (label, sensors[id]["Lower Critical Threshold"], sensors[id]["Upper Critical Threshold"])
190
191 #            pprint.pprint(sensors[id])
192     sys.exit(0)
193
194 def fetch():
195     sensors = read_sensors()
196
197     for id in sorted(sensors):
198         if sensors[id]["Group Name"] == mode:
199             label = normalize_sensor(sensors[id]["Sensor Name"])
200             print "%s.value %s" % (label, sensors[id]["Sensor Reading"].split(".")[0])
201     sys.exit(0)
202
203
204 if "config" in sys.argv[1:]:
205     print_config()
206
207 elif "autoconf" in sys.argv[1:]:
208     bmc_detect()
209
210 elif "suggest" in sys.argv[1:]:
211     sensors = read_sensors()
212     fan, temperature = [0, 0]
213     for id in sensors:
214         if sensors[id]["Group Name"] == "Fan":
215             fan += 1
216         elif sensors[id]["Group Name"] == "Temperature":
217             temperature += 1
218     if fan > 0:
219         print "fan"
220     if temperature > 0:
221         print "temp"
222     sys.exit(0)
223
224 else:
225     fetch()
Note: See TracBrowser for help on using the browser.