For the v1.6 the documentation about plugins was/is almost nonexisting, so I wrote my custom check plugin for checking disk status on DELL BOSS card by reading other checks and with try/error method.
Now, I would like to write plugin for Adaptec RAID controllers which we use in our servers and would like to use parse function. So I tried to write it according official ‘megaraid_pdisks’ plugin. I would like to send multi line output from agent and to the parse of data by plugin. But I don’t understand what is going in background with parse function and my code doesn’t work and can’t figure it out why.
Is there any documentation or someones personal notes available about parse function?
Docu for v2 is better, but API is completely different, so not usable for me.
The parse_function gets the “raw” agent data before the inventory_function or check_function are called. They become the output of the parse_function instead.
Unfortunately I don’t understand how it works, and don’t understand why it doesn’t work fully properly, means why check_mk didn’t parsed the output properly.
def adaptec_raid_parse(info):
return_var = []
for line in info:
if line[0] == 'Controller' and line[1] == 'Status:':
state = line[2:]
elif line[0] == 'Controller' and line[1] == 'Model:':
model = line[2:]
elif line[0] == 'Controller' and line[1] == 'Serial' and line[2] == 'Number:':
serial = line[3:]
elif line[0] == 'PCI' and line[1] == 'Device' and line[2] == 'ID:':
devid = line[3]
return_var.append((devid, state, model))
return return_var
# inventory
def inventory_adaptec_raid(info):
info = adaptec_raid_parse(info)
inventory = []
for devid, state, model in info:
inventory.append(("%s" % devid, None))
return inventory
#print info
# check
def check_adaptec_raid(item, _no_params, info):
info = adaptec_raid_parse(info)
for devid, state, model in info:
if "%s" % devid == item:
infotext = "%s %s" % (state, model)
return 0, infotext
#return 3, "No controller found. - %d" % item
# declare
check_info["adaptec_raid"] = {
'check_function': check_adaptec_raid,
'inventory_function': inventory_adaptec_raid,
'service_description': 'RAID Controller %s',
}
You need to define the parse function whithin the check_info structure. Then checkmk will call it automatically for you. The data flow then is:
The parse function gets called with the raw agent output as a list of lists (line by line and separated at whitespace). The parse function must return “something”, usually either a dictionary with the items as keys or a list.
The inventory function gets called with the return value of the parse_function. It must return every item found (in case of a service with items). So the easiest is to just iterate the dictionary which the parse function returned and return its keys.
The check function gets called with an item (one that was determined by the inventory function) and the return value of the parse function. It can thus just check the values of parsed[item].
I’d try this approach:
# <<<adaptec_raid>>>
# Controller Status: Optimal
# Controller Model: Adaptec ASR8885
# Controller Serial Number: 6A506399A1D
# PCI Device ID: 653
def adaptec_raid_parse(info):
parsed = {}
state, model, serial, devid = None, None, None, None
for line in info:
if line[0] == 'Controller' and line[1] == 'Status:':
state = ' '.join(line[2:])
elif line[0] == 'Controller' and line[1] == 'Model:':
model = ' '.join(line[2:])
elif line[0] == 'Controller' and line[1] == 'Serial' and line[2] == 'Number:':
serial = ' '.join(line[3:])
elif line[0] == 'PCI' and line[1] == 'Device':
devid = int(line[-1])
if state and model and serial:
parsed[devid] = (state, model, serial)
state, model, serial = None, None, None
# now parsed is a dictionary.
# { 653: ('Optimal', 'Adaptec ASR8885', '6A506399A1D') }
# if you have multiple PCI devices, it would look like this:
# { 653: ('Optimal', 'Adaptec ASR8885', '6A506399A1D'),
# 123: ('Even Better', 'Adaptec xxxx', 'yyyyy') }
return parsed
# inventory. gets called with the return value of the parse function.
# it returns one item (=device-id) at a time.
def inventory_adaptec_raid(parsed):
for item in parsed.keys():
yield item, None
# check. gets called with the return value of the parse function.
def check_adaptec_raid(item, params, parsed):
if not parsed or item not in parsed:
return # this indicates "UNKN - Item not found"
# now parsed[item] contains the data for this particular item (aka device-id). so:
yield 0, parsed[item][0] # state
yield 0, "model=%s" % parsed[item][1] # model
yield 0, "serial=%s" % parsed[item][2] # serial
# declare
check_info["adaptec_raid"] = {
'parse_function': adaptec_raid_parse,
'check_function': check_adaptec_raid,
'inventory_function': inventory_adaptec_raid,
'service_description': 'RAID Controller %s',
}
@Dirk This is awesome. Thank you very much for example and especially comments. It makes more clear now, how it works.
I made small change and put Adapter model into Service description instead of Device ID and change yield’s to one return statement (also modified the parse function accordingly).
# check. gets called with the return value of the parse function.
def check_adaptec_raid(item, params, parsed):
if not parsed or item not in parsed:
return # this indicates "UNKN - Item not found"
# now parsed[item] contains the data for this particular item (aka device-id). so:
#yield 0, parsed[item][0] # state
#yield 0, "model=%s" % parsed[item][1] # model
#yield 0, "serial=%s" % parsed[item][2] # serial
state = parsed[item][0]
if state == 'Optimal':
retval = 0
else:
retval = 2
infotext = "Status=%s, PCI Device ID=%s, Serial=%s" % (parsed[item][0], parsed[item][1], parsed[item][2])
return retval, infotext
You’re welcome. Yes, of course there are many ways to write such a plugin. I think one of the things that confused you was a snippet like this:
serial = line[3:]
Here serial is a list of things, i.e. if line is e.g. ['a', 'b', 'c', 'd'], then serial now is ['d']. That’s why it showed up as [u'ASR8885'] (or similar) in the GUI. I re-joined the elements in that list with space characters (serial=' '.join(line[3:]) to get a simple string.
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed. Contact an admin if you think this should be re-opened.