Projet

Général

Profil

Révision fc51c3a6

IDfc51c3a69eb6d3106b9c01fdc3abcc11ffbd4be0
Parent 6eebc571
Enfant acb3839b

Ajouté par Andreas Thienemann il y a presque 14 ans

Initial version

Voir les différences:

plugins/other/freeipmi_
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
            print "%s.graph_args --base 1000 -l 0" % (label)
191
            print "%s.graph_scale no" % (label)
192
#            pprint.pprint(sensors[id])
193
    sys.exit(0)
194

  
195
def fetch():
196
    sensors = read_sensors()
197

  
198
    for id in sorted(sensors):
199
        if sensors[id]["Group Name"] == mode:
200
            label = normalize_sensor(sensors[id]["Sensor Name"])
201
            print "%s.value %s" % (label, sensors[id]["Sensor Reading"].split(".")[0])
202
    sys.exit(0)
203

  
204

  
205
if "config" in sys.argv[1:]:
206
    print_config()
207

  
208
elif "autoconf" in sys.argv[1:]:
209
    bmc_detect()
210

  
211
elif "suggest" in sys.argv[1:]:
212
    sensors = read_sensors()
213
    fan, temperature = [0, 0]
214
    for id in sensors:
215
        if sensors[id]["Group Name"] == "Fan":
216
            fan += 1
217
        elif sensors[id]["Group Name"] == "Temperature":
218
            temperature += 1
219
    if fan > 0:
220
        print "fan"
221
    if temperature > 0:
222
        print "temp"
223
    sys.exit(0)
224

  
225
else:
226
    fetch()

Formats disponibles : Unified diff