Custom snmp check for digium switchvox - not getting right output

hi everyone,

been working on creating a check for digium switchvox and could use some help as my python-fu is terrible. I’m trying to create a check that inventories the different providers that are configured, their current state and latency with perfdata. I haven’t gotten to the perfdata portion just yet. So far I have a check that does inventory the providers but I can’t get the status to output correctly:

def list_split(length, number):
	for i in range(0, len(length), number):
		yield length[i:i+number]

def inventory_digium_providers(info):
	info_split = list(list_split(info, 8))
	import pprint ; pprint.pprint(info)
	for id, type, name, host, account_id, cb_ext, latency, state in info_split:
		yield str(name[0]), None
	
def check_digium_providers(item, _no_params, info):
	info_split = list(list_split(info, 8))
	for id, type, name, host, account_id, cb_ext, latency, state in info_split:
			if state[0] == "ok" or state[0] == "registered":
				yield 0, "Status: %s" % state[0]

	
check_info["digium_providers"] = {
	"check_function"		:	check_digium_providers,
	"inventory_function"	:	inventory_digium_providers,
	"service_description"	:	"Provider %s",
	"has_perfdata"	:	True,
    "snmp_info": ( ".1.3.6.1.4.1.22736.10.2", ["3"] ),
	"snmp_scan_function": lambda oid: oid(".1.3.6.1.4.1.22736.10.1.1") is not None
}

Basically this outputs the following:

OK - Status: ok, Status: registered

In this example, I have two providers, one shows as status ok and the other shows as registered in the switchvox console. Don’t know enough about python to know why these two outputs are getting combined.

Please show the output of "cmk --snmpwalk " for the OID .1.3.6.1.4.1.22736.10.2, otherwise it is not possible to follow your implementation.

One thing already seems to be not correct is your check function which does not use the item.

Here’s the output:

.1.3.6.1.4.1.22736.10.2.1 = INTEGER: 2
.1.3.6.1.4.1.22736.10.2.2 = INTEGER: 2
.1.3.6.1.4.1.22736.10.2.3.1.1 = INTEGER: 101
.1.3.6.1.4.1.22736.10.2.3.1.2 = STRING: "SIP"
.1.3.6.1.4.1.22736.10.2.3.1.3 = STRING: "Gateway1"
.1.3.6.1.4.1.22736.10.2.3.1.4 = STRING: "10.10.10.10"
.1.3.6.1.4.1.22736.10.2.3.1.5 = STRING: "admin"
.1.3.6.1.4.1.22736.10.2.3.1.6 = INTEGER: 0
.1.3.6.1.4.1.22736.10.2.3.1.7 = STRING: "53.523"
.1.3.6.1.4.1.22736.10.2.3.1.8 = STRING: "ok"
.1.3.6.1.4.1.22736.10.2.3.2.1 = INTEGER: 102
.1.3.6.1.4.1.22736.10.2.3.2.2 = STRING: "SIP"
.1.3.6.1.4.1.22736.10.2.3.2.3 = STRING: "Gateway2"
.1.3.6.1.4.1.22736.10.2.3.2.4 = STRING: "10.10.10.2"
.1.3.6.1.4.1.22736.10.2.3.2.5 = STRING: "mtyadmin"
.1.3.6.1.4.1.22736.10.2.3.2.6 = INTEGER: 899
.1.3.6.1.4.1.22736.10.2.3.2.7 = STRING: "2.286"
.1.3.6.1.4.1.22736.10.2.3.2.8 = STRING: "registered"

Like I mentioned, my python-fu sucks pretty bad. Been starting to learn it since it’s definitely useful but I don’t really know how to use that “item” variable in this case. Tried to look at other examples but I’m just not understanding it.

The vendor really messed up the SNMP data. This is very uncommon. Usually the data should look like:

.1.3.6.1.4.1.22736.10.2.1 = INTEGER: 2
.1.3.6.1.4.1.22736.10.2.2 = INTEGER: 2
.1.3.6.1.4.1.22736.10.2.3.1.1 = INTEGER: 101
.1.3.6.1.4.1.22736.10.2.3.1.2 = INTEGER: 102
.1.3.6.1.4.1.22736.10.2.3.2.1 = STRING: "SIP"
.1.3.6.1.4.1.22736.10.2.3.2.2 = STRING: "SIP"
.1.3.6.1.4.1.22736.10.2.3.3.1 = STRING: "Gateway1"
.1.3.6.1.4.1.22736.10.2.3.3.2 = STRING: "Gateway2"
.1.3.6.1.4.1.22736.10.2.3.4.1 = STRING: "10.10.10.10"
.1.3.6.1.4.1.22736.10.2.3.4.2 = STRING: "10.10.10.2"
.1.3.6.1.4.1.22736.10.2.3.5.1 = STRING: "admin"
.1.3.6.1.4.1.22736.10.2.3.5.2 = STRING: "mtyadmin"
.1.3.6.1.4.1.22736.10.2.3.6.1 = INTEGER: 0
.1.3.6.1.4.1.22736.10.2.3.6.2 = INTEGER: 899
.1.3.6.1.4.1.22736.10.2.3.7.1 = STRING: "53.523"
.1.3.6.1.4.1.22736.10.2.3.7.2 = STRING: "2.286"
.1.3.6.1.4.1.22736.10.2.3.8.1 = STRING: "ok"
.1.3.6.1.4.1.22736.10.2.3.8.2 = STRING: "registered"

This is a dirty version, as it has to transpose the list of lists returned by the SNMP query because the vendor really does not understand SNMP…

#!/usr/bin/env python
# -*- encoding: utf-8; py-indent-offset: 4 -*-

def parse_digium_providers(info):
    import cmk.utils.debug
    if cmk.utils.debug.enabled():
        pprint.pprint(info)
    return map(list, zip(*info))[1:]

def inventory_digium_providers(parsed):
    import cmk.utils.debug
    if cmk.utils.debug.enabled():
        pprint.pprint(parsed)
    for line in parsed:
        if line[2]:
            yield line[2], {}
	
def check_digium_providers(item, _no_params, parsed):
    for line in parsed:
        if item == line[2]:
            yield 0, "ID: %s" % line[0], [ ( "average_latency", float(line[6])) ]
            yield 0, "type: %s" % line[1]
            yield 0, "IP: %s" % line[3]
            if line[7] not in ["ok", "registered"]:
                yield 2, "state is %s" % line[7]
	
check_info["digium_providers"] = {
    "parse_function"      : parse_digium_providers,
    "check_function"      : check_digium_providers,
    "inventory_function"  : inventory_digium_providers,
    "service_description" : "Provider %s",
    "has_perfdata"        : True,
    "snmp_info"           : ( ".1.3.6.1.4.1.22736.10.2.3", xrange(255) ),
    "snmp_scan_function"  : lambda oid: oid(".1.3.6.1.4.1.22736.10.1.1") is not None
}

As how the snmp_info is implemented there is a maximum of 255 providers possible.

I am happy if someone is able to find a better implementation.

It seems to work but, as you said, it’s a dirty version. There’s a lot of these:

[u'', u'', u'', u'', u'', u'', u'', u''],
 [u'', u'', u'', u'', u'', u'', u'', u''],
 [u'', u'', u'', u'', u'', u'', u'', u''],
 [u'', u'', u'', u'', u'', u'', u'', u''],

and a lot of these:

  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',
  u'',

I’m guessing I could just remove these two lines from the parse and inventory functions to avoid see that, right?

if cmk.utils.debug.enabled():
        pprint.pprint(info)

The debug output is only shown when running “cmk --debug”. And yes, you can remove all these lines.