This file is indexed.

/usr/share/check_mk/checks/ipmi is in check-mk-server 1.2.8p16-1ubuntu0.1.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
#!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# |             ____ _               _        __  __ _  __           |
# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           |
# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            |
# |           | |___| | | |  __/ (__|   <    | |  | | . \            |
# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           |
# |                                                                  |
# | Copyright Mathias Kettner 2014             mk@mathias-kettner.de |
# +------------------------------------------------------------------+
#
# This file is part of Check_MK.
# The official homepage is at http://mathias-kettner.de/check_mk.
#
# check_mk 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 in version 2.  check_mk is  distributed
# in the hope that it will be useful, but WITHOUT ANY WARRANTY;  with-
# out even the implied warranty of  MERCHANTABILITY  or  FITNESS FOR A
# PARTICULAR PURPOSE. See the  GNU General Public License for more de-
# tails. You should have  received  a copy of the  GNU  General Public
# License along with GNU Make; see the file  COPYING.  If  not,  write
# to the Free Software Foundation, Inc., 51 Franklin St,  Fifth Floor,
# Boston, MA 02110-1301 USA.


# Example of output from ipmi:
# <<<ipmi>>>
# ambienttemp 25.800 degrees_C ok na na na 34.800 40.200 na
# bulk.v12-0-s0 11.940 Volts ok na 10.200 na na 13.800 na
# bulk.v3_3-s0 3.360 Volts ok na 3.000 na na 3.600 na
# bulk.v3_3-s5 3.240 Volts ok na 3.000 na na 3.600 na
# bulk.v5-s0 5.040 Volts ok na 4.500 na na 5.520 na
# bulk.v5-s5 5.040 Volts ok na 4.500 na na 5.520 na
# cpu0.dietemp 51.000 degrees_C ok na na na 70.200 73.200 na
# ...
# On another host
# mb.t_amb 24.000 degrees_C ok na na na 70.000 75.000 80.000
# mb.v_bat 2.839 Volts ok 2.340 2.527 2.621 3.307 3.510 3.697
# mb.v_+3v3stby 3.218 Volts ok 2.595 2.785 2.993 3.598 3.789 3.996
# mb.v_+3v3 3.339 Volts ok 2.595 2.785 2.993 3.598 3.789 3.996
# mb.v_+5v 5.044 Volts ok 3.484 3.978 4.498 5.486 5.980 6.500
# fp.t_amb 21.000 degrees_C ok na na na 30.000 35.000 45.000
# pdb.t_amb 21.000 degrees_C ok na na na 70.000 75.000 80.000
# io.t_amb 19.000 degrees_C ok na na na 70.000 75.000 80.000
# p0.t_core 18.000 degrees_C ok na na na 62.000 67.000 75.000
# p0.v_vdd 1.332 Volts ok 0.792 0.900 0.996 1.596 1.692 1.800

# Yet another host (HP DL 360G5)
# <<<ipmi>>>
# UID_Light 0.000 unspecified ok na na 0.000 na na na
# Int._Health_LED 0.000 unspecified ok na na 0.000 na na na
# Ext._Health_LED 0.000 unspecified ok na na 0.000 na na na
# Power_Supply_1 0.000 unspecified nc na na 0.000 na na na
# Power_Supply_2 0.000 unspecified nc na na 0.000 na na na
# Power_Supplies 0.000 unspecified nc na na 0.000 na na na
# VRM_1 0.000 unspecified cr na na 0.000 na na na
# VRM_2 0.000 unspecified cr na na 0.000 na na na
# Fan_Block_1 34.888 unspecified nc na na 75.264 na na na
# Fan_Block_2 29.792 unspecified nc na na 75.264 na na na
# Fan_Block_3 34.888 unspecified nc na na 75.264 na na na
# Fan_Blocks 0.000 unspecified nc na na 0.000 na na na
# Temp_1 39.000 degrees_C ok na na -64.000 na na na
# Temp_2 16.000 degrees_C ok na na -64.000 na na na
# Temp_3 30.000 degrees_C ok na na -64.000 na na na
# Temp_4 30.000 degrees_C ok na na -64.000 na na na
# Temp_5 25.000 degrees_C ok na na -64.000 na na na
# Temp_6 30.000 degrees_C ok na na -64.000 na na na
# Temp_7 30.000 degrees_C ok na na -64.000 na na na
# Power_Meter 180.000 Watts cr na na 384.000 na na na

# And this host has some false-criticals (PowerMeter, VirtualFan)
# <<<ipmi>>>
# Temp_1 17.000 degrees_C ok 0.000 0.000 0.000 40.000 42.000 46.000
# Temp_2 40.000 degrees_C ok 0.000 0.000 0.000 0.000 82.000 83.000
# Temp_3 44.000 degrees_C ok 0.000 0.000 0.000 0.000 82.000 83.000
# Temp_4 52.000 degrees_C ok 0.000 0.000 0.000 0.000 87.000 92.000
# Temp_5 46.000 degrees_C ok 0.000 0.000 0.000 0.000 85.000 90.000
# Temp_6 55.000 degrees_C ok 0.000 0.000 0.000 0.000 85.000 90.000
# Temp_7 51.000 degrees_C ok 0.000 0.000 0.000 0.000 85.000 90.000
# Temp_8 58.000 degrees_C ok 0.000 0.000 0.000 0.000 78.000 83.000
# Temp_9 74.000 degrees_C ok 0.000 0.000 0.000 0.000 110.000 115.000
# Temp_10 31.000 degrees_C ok 0.000 0.000 0.000 0.000 60.000 65.000
# Virtual_Fan 19.600 unspecified nc na na na na na na
# Power_Meter 236.000 Watts cr na na na na na na

# IPMI has two operation modes:
# 1. detailed
# 2. summarized
# This controls how the inventory is done. In summary-mode, the
# inventory returns one single check item 'Summary' - or nothing
# if the host does not send any IPMI information
# In Detailed mode for each sensor one item is returned.

# Newer output formats (sensor list and compact/discrete sensors)
# <<<ipmi:sep(124)>>>
# BB +5V           | 5.070      | Volts      | ok    | na        | 4.446     | 4.576     | 5.408     | 5.564     | na
# BB +12V AUX      | 11.904     | Volts      | ok    | na        | 10.416    | 10.726    | 13.144    | 13.578    | na
# BB +0.9V         | 0.898      | Volts      | ok    | na        | 0.811     | 0.835     | 0.950     | 0.979     | na
# Serverboard Temp | 39.000     | degrees C  | ok    | na        | 5.000     | 10.000    | 61.000    | 66.000    | na
# Ctrl Panel Temp  | 31.000     | degrees C  | ok    | na        | 0.000     | 5.000     | 44.000    | 48.000    | na
# Fan 1            | 7740.000   | RPM        | ok    | na        | 1720.000  | 1978.000  | na        | na        | na
# Fan 2            | 8557.000   | RPM        | ok    | na        | 1720.000  | 1978.000  | na        | na        | na
# Fan 3            | 7611.000   | RPM        | ok    | na        | 1720.000  | 1978.000  | na        | na        | na
# <<<ipmi_discrete:sep(124)>>>
# PS3 Status       | C8h | ok | 10.1 | Presence detected
# PS4 Status       | C9h | ok | 10.2 | Presence detected
# Pwr Unit Stat    | 01h | ok | 21.1 |
# Power Redundancy | 02h | ok | 21.1 | Fully Redundant
# BMC Watchdog     | 03h | ok |  7.1 |
# PS1 Status       | C8h | ok | 10.1 | Presence detected, Failure detected     <= NOT OK !!
# PS2 Status       | C9h | ok | 10.2 | Presence detected

# broken
# <<<ipmi:cached(1472175405,300)>>>
# 01-Inlet_Ambient 18.000 degrees_C ok na na na na 42.000 46.000
# 02-CPU_1 40.000 degrees_C ok na na na na 70.000 na
# 03-CPU_2 40.000 degrees_C ok na na na na 70.000 na
# 04-DIMM_P1_1-3 32.000 degrees_C ok na na na na 87.000 na
# 05-DIMM_P1_4-6 32.000 degrees_C ok na na na na 87.000 na
# 06-DIMM_P2_1-3 27.000 degrees_C ok na na na na 87.000 na
# 07-DIMM_P2_4-6 26.000 degrees_C ok na na na na 87.000 na
# 09-Chipset 47.000 degrees_C ok na na na na 105.000 na
# 10-VR_P1 32.000 degrees_C ok na na na na 115.000 120.000
# 11-VR_P2 27.000 degrees_C ok na na na na 115.000 120.000
# 12-VR_P1_Zone 27.000 degrees_C ok na na na na 80.000 85.000
# 13-VR_P2_Zone 25.000 degrees_C ok na na na na 80.000 85.000
# 14-VR_P1_Mem 33.000 degrees_C ok na na na na 115.000 120.000
# 15-VR_P2_Mem 23.000 degrees_C ok na na na na 115.000 120.000
# 16-VR_P1Mem_Zone 32.000 degrees_C ok na na na na 80.000 85.000
# 17-VR_P2Mem_Zone 22.000 degrees_C ok na na na na 80.000 85.000
# 18-HD_Controller 57.000 degrees_C ok na na na na 90.000 na
# 19-Supercap 32.000 degrees_C ok na na na na 65.000 na
# 21-PCI_Zone 30.000 degrees_C ok na na na na 80.000 85.000
# 23-I/O_1_Zone 28.000 degrees_C ok na na na na 80.000 85.000
# 26-I/O_LOM 40.000 degrees_C ok na na na na 100.000 na
# 27-Sys_Exhaust 31.000 degrees_C ok na na na na 80.000 85.000
# PS3_Inpu


ipmi_summarize = True
ipmi_ignore_nr = False # set to True in order to ignore entries with state 'nr'
ipmi_ignored_sensors = [] # example: [ "Power_Meter", "Virtual_Fan" ]
inventory_ipmi_rules = []


def ipmi_get_ignored_sensors(hostname):
    # merge ignored sensor list specified here and those from wato
    ignored_sensors_combined = ipmi_ignored_sensors[:]
    rules = host_extra_conf(hostname, inventory_ipmi_rules)
    if rules:
        ignored_sensors_combined += rules[0].get("ignored_sensors", [])

    return ignored_sensors_combined


def ipmi_ignore_entry(name, state, ignored_sensors):
    if ipmi_ignore_nr and (state.startswith('nr') or state.startswith('ns')):
        return True

    for e in ignored_sensors:
        if name.startswith(e):
            return True

    return False


def parse_ipmi(info):
    ipmi_info, ipmi_discrete_info = info
    parsed = []
    for section in [ ipmi_info, ipmi_discrete_info ]:
        if section:
            for line in section:
                if len(line) >= 2:
                    # Compatible with older check versions
                    name = line[0].strip().replace(" ", "_")
                    line = [ name ] + map(lambda x: x.strip(), line[1:])

                    # Discrete sensors have no values
                    if len(line) == 5:
                        state = line[2]
                        if line[4]:
                            state += " (%s)" % line[4]
                        line = [line[0], None, None, state, None, None, None, None, None, None]

                if len(line) == 10:
                    parsed.append(line)

    return parsed


def inventory_ipmi(info):
    parsed = parse_ipmi(info)
    summarize = True
    rules = host_extra_conf(g_hostname, inventory_ipmi_rules)
    if rules:
        summarize = rules[0].get("summarize", True)

    # the default for summarize is always true so if either configuration key has been set
    # to false that setting was changed by the user and needs to override the other
    if not ipmi_summarize or not summarize or len(parsed) == 0:
        ignored_sensors = ipmi_get_ignored_sensors(g_hostname)
        for line in parsed:
            if not ipmi_ignore_entry(line[0], line[3], ignored_sensors):
                yield line[0], None
    else:
        yield "Summary", None


def check_ipmi(item, params, info):
    parsed = parse_ipmi(info)
    if item == "Summary":
        return check_ipmi_summarized(parsed, params)
    else:
        return check_ipmi_detailed(item, parsed)


def ipmi_format_message(status, val, unit):
    infotext = status

    # otherwise the unit is unknown or there is none (val could represent yes/no)
    if val is not None:
        infotext += ", %s" % val

    if unit not in [ 'unspecified', None ]:
        infotext += " %s" % unit

    return infotext


def check_ipmi_detailed(item, parsed):
    for name, val, unit, status, unrec_low, crit_low, \
        warn_low, warn_high, crit_high, unrec_high in parsed:

        if name == item:
            if val is not None:
                perfdata = [ (name, val + unit, warn_high, crit_high) ]
            else:
                perfdata = []

            if status.startswith('ok') and not "failure detected" in status.lower():
                state = 0
            elif status.startswith('nc'):
                state = 1
            else:
                state = 2

            return state, "Status: %s" % ipmi_format_message(status, val, unit), perfdata


def check_ipmi_summarized(parsed, params):
    worst_status  = 0
    warn_texts    = []
    crit_texts    = []
    count         = 0
    ambient_count = 0
    ambient_sum   = 0.0

    if 'ignored_sensors' not in params:
        params['ignored_sensors'] = ipmi_get_ignored_sensors(g_hostname)

    for name, val, unit, status, unrec_low, crit_low, \
        warn_low, warn_high, crit_high, unrec_high in parsed:

        # Skip datasets which have no valid data (zero value, no unit and state nc)
        if val == '0.000' and unit == 'unspecified' and status.startswith('nc'):
            continue

        if ipmi_ignore_entry(name, status, params['ignored_sensors']):
            continue

        count += 1
        infotext = "%s (%s)" % (name, ipmi_format_message(status, val, unit))

        if status.startswith('nc'):
            worst_status = max(worst_status, 1)
            warn_texts.append(infotext)

        elif status.startswith('nr') and ipmi_ignore_nr:
            pass

        elif not status.startswith('ok') or "failure detected" in status.lower():
            worst_status = 2
            crit_texts.append(infotext)

        if "amb" in name or "Ambient" in name:
            try:
                ambient_count += 1
                ambient_sum += float(val)
            except:
                pass

    if ambient_count > 0:
        perfdata = [ ("ambient_temp", ambient_sum / ambient_count) ]
    else:
        perfdata = []

    if worst_status == 0:
        infotexts = [ "%d sensors OK" % count ]

    else:
        infotexts = []
        if len(crit_texts) > 0:
            infotexts.append("CRIT are: %s" % ", ".join(crit_texts))
        if len(warn_texts) > 0:
            infotexts.append("WARN are: %s" % ", ".join(warn_texts))

    return worst_status, ' - '.join(infotexts), perfdata


def ipmi_precompile(hostname, item, params):
    if params is not None:
        precomped = params.copy()
    else:
        precomped = {}

    precomped['ignored_sensors'] = ipmi_get_ignored_sensors(hostname)
    return precomped


# Make sure, configuration variables needed during check time are present
# in precompiled code
check_config_variables.append("ipmi_ignore_nr")
check_config_variables.append("ipmi_ignored_sensors")


check_info["ipmi"] = {
    'inventory_function'  : inventory_ipmi,
    'check_function'      : check_ipmi,
    'service_description' : 'IPMI Sensor %s',
    'has_perfdata'        : True,
    'extra_sections'      : [ "ipmi_discrete" ],
}


precompile_params['ipmi'] = ipmi_precompile