Plugin detected with CLI but now with WebUI

2.4.0
Debian 12

I am trying to update this plugin to be used with the plugin API 2.0 :

I successfully updated the agent_based python to this :

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
 

from dataclasses import dataclass
from typing import Dict
from cmk.agent_based.v2 import (
    AgentSection,
    CheckPlugin,
    CheckResult,
    DiscoveryResult,
    Result,
    Service,
    State,
    StringTable,
    SimpleSNMPSection,
    SNMPTree,
    exists,
    Metric
)

@dataclass
class OspfNeighbor:
    rtrid: str
    options: str
    prio: str
    state: str
    events: int
    lsretransqlen: int
    permanence: str
    hellosup: str
    helperstatus: str
    helperage: str
    helperexitreason: str


def parse_ospf_neighbor(string_table: StringTable) -> Dict[str, OspfNeighbor]:
    def ospf_nbr_hellosuppressed(st: str) -> str:
        names = {'1': 'true',
                 '2': 'false'}
        return names.get(st, st)

    def ospf_nbr_permanence(st: str) -> str:
        names = {'1': 'dynamic',
                 '2': 'permanent'}
        return names.get(st, st)

    def ospf_nbr_helperstatus(st: str) -> str:
        names = {'1': 'notHelping',
                 '2': 'helping'}
        return names.get(st, st)

    def ospf_nbr_helperexitreason(st: str) -> str:
        names = {'1': 'none',
                 '2': 'inProgress',
                 '3': 'completed',
                 '4': 'timedOut',
                 '5': 'topologyChanged'}
        return names.get(st, st)

    def ospf_nbr_options(st: str) -> str:
        """
        A bit mask corresponding to the neighbor's options field.
        Bit 0, if set, indicates that the system will operate on Type of Service metrics other than TOS 0.
               If zero, the neighbor will ignore all metrics except the TOS 0 metric.
        Bit 1, if set, indicates that the associated area accepts and operates on external information;
               if zero, it is a stub area.
        Bit 2, if set, indicates that the system is capable of routing IP multicast datagrams, that is that it
               implements the multicast extensions to OSPF.
        Bit 3, if set, indicates that the associated area is an NSSA. These areas are capable of carrying type-7
               external advertisements, which are translated into type-5 external advertisements at NSSA borders.
        """
        try:
            st = ord(st)
        except TypeError:
            return 'unknown'

        options = []
        for key, value in [
            (1, 'non TOS 0 service metrics accepted'),
            (2, 'not a stub area'),
            (4, 'IP multicast routing capable'),
            (8, 'is NSSA'),
        ]:
            if st & key == key:
                options.append(value)

        options = ', '.join(options)
        if options == '':
            return 'unknown'
        else:
            return options

    parsed = {}
    for ip, rtrid, options, prio, state, events, lsretransqlen, permanence, hellosup, helperstatus, helperage, \
        helperexitreason in string_table:
        parsed[ip] = OspfNeighbor(
            rtrid=rtrid,
            options=ospf_nbr_options(options),
            prio=prio,
            state=state,
            events=int(events),
            lsretransqlen=int(lsretransqlen),
            permanence=ospf_nbr_permanence(str(permanence)),
            hellosup=ospf_nbr_hellosuppressed(hellosup),
            helperstatus=ospf_nbr_helperstatus(helperstatus),
            helperage=helperage,
            helperexitreason=ospf_nbr_helperexitreason(helperexitreason),
        )
    return parsed


def discovery_ospf_neighbor(section: Dict[str, OspfNeighbor]) -> DiscoveryResult:
    for neighbor in section.keys():
        yield Service(item=neighbor)


def check_ospf_neighbor(item, params, section: Dict[str, OspfNeighbor]) -> CheckResult:
    def ospf_nbr_state(st: str) -> str:
        names = {
            '1': 'down',
            '2': 'attempt',
            '3': 'init',
            '4': 'twoWay',
            '5': 'exchangeStart',
            '6': 'exchange',
            '7': 'loading',
            '8': 'full'
        }
        return names.get(st, 'unknown: %s' % st)
    neighborstate = {
        '1': 2,  
        '2': 1,  
        '3': 1,  
        '4': 0,  
        '5': 1,  
        '6': 1,  
        '7': 1,  
        '8': 0,  
    }

    not_found_state = params['state_not_found']

    for neighbour, neighbourAlias, neighbourNotFoundState in params.get('peer_list', []):
        if item == neighbour:
            yield Result(state=State.OK, summary=f'[{neighbourAlias}]')
            not_found_state = neighbourNotFoundState

    try:
        neighbor = section[item]
    except KeyError:
        yield Result(state=State(not_found_state), notice='Item not found in SNMP data')
        return

    yield Result(state=State.OK, summary=f'Neighbor ID: {neighbor.rtrid}')

    neighborstate.update(params.get('neighborstate', neighborstate))  # update neighborstatus with params

    yield Result(state=State(neighborstate.get(neighbor.state, 3)), summary=f'Status: {ospf_nbr_state(neighbor.state)}')

    yield Metric(value=neighbor.events, name='ospf_neighbor_ospf_events')
    yield Metric(value=neighbor.lsretransqlen, name='ospf_neighbor_ospf_retransmission_queue_length')

    for text, value in [
        ('options', neighbor.options),
        ('priority', neighbor.prio),
        ('permanence', neighbor.permanence),
        ('hello suppressed', neighbor.hellosup),
        ('helper status', neighbor.helperstatus),
        ('helper age', neighbor.helperage),
        ('helper exit reason', neighbor.helperexitreason),
    ]:
        if value != '':
            yield Result(state=State.OK, notice=f'Neighbor {text}: {value}')


snmp_section_ospf_neighbor = SimpleSNMPSection(
    name='ospf_neighbor',
    parse_function=parse_ospf_neighbor,
    fetch=SNMPTree(
        base=".1.3.6.1.2.1.14.10.1",   
        oids=[
            '1', 
            '3', 
            '4', 
            '5', 
            '6', 
            '7', 
            '8', 
            '10',
            '11',
            '12',
            '13',
            '14',
        ]
    ),
    detect=exists('.1.3.6.1.2.1.14.10.1.1.*')
)

check_plugin_ospf_neighbor = CheckPlugin(
    name='ospf_neighbor',
    service_name='OSPF neighbor %s',
    discovery_function=discovery_ospf_neighbor,
    check_function=check_ospf_neighbor,
    check_default_parameters={
        'state_not_found': 3,
    },
    check_ruleset_name='ospf_neighbor',
)

I changed the path of the plugin to ~/local/lib/python3/cmk_addons/plugins/ospf_neighbor/agent_base

The plugin is working fine when using the cli cmk :

OMD[prod]:~/local/lib/python3/cmk_addons/plugins/ospf_neighbor/agent_based$ cmk -vI --detect-plugins=ospf_neighbor routeur
Discovering services and host labels on: routeur
routeur:
+ FETCHING DATA
Get piggybacked data
+ ANALYSE DISCOVERED HOST LABELS
SUCCESS - Found no new host labels
+ ANALYSE DISCOVERED SERVICES
+ EXECUTING DISCOVERY PLUGINS (1)
  5 ospf_neighbor
SUCCESS - Found 5 services
OMD[prod]:~/local/lib/python3/cmk_addons/plugins/ospf_neighbor/agent_based$ cmk -v --detect-plugins=ospf_neighbor routeur
+ FETCHING DATA
Get piggybacked data
OSPF neighbor 5.182.144.18 Neighbor ID: ****, Status: twoWay
OSPF neighbor 5.182.144.19 Neighbor ID: ****, Status: twoWay
OSPF neighbor 5.182.144.20 Neighbor ID: ****, Status: full
OSPF neighbor 5.182.144.21 Neighbor ID: ****, Status: twoWay
OSPF neighbor 5.182.144.22 Neighbor ID: ****, Status: full
[snmp] Success, [piggyback] Success (but no data found for this host), execution time 0.1 sec | execution_time=0.090 user_time=0.070 system_time=0.000 children_user_time=0.000 children_system_time=0.000 cmk_time_snmp=0.030 cmk_time_agent=0.000

But when i go to the Run Discovery Page, the services appear at Unknown state :

I have the same problem with another plugin.

Did i miss something to the new Plugin API ?

CheckMK created Python Compiled versions (.pyc) of all plugins. Outdated versions of the compiled version have bitten me in the past. If you have not fully restarted your site, that is a quick way to check to see if that is your issue. If it is, you’ll have to do that after changes to ensure you have the latest version.

If someone else has a better way to deal with old pyc files, I’m all ears.

Hi,

Thanks for the fast answer.
I did this after each modification :

cmk -R && omd restart redis && omd restart apache

Is that what you are talking about ?
Also this plugin wasn’t previously installed on this site.

I went a bit further after having a lot of issues with this when developing a large group of new plugins for a client.

The following is to be used at your own risk. While it has not caused issues for me, I don’t promise it won’t for you

find ~/local/lib/python3/cmk_addons/plugins/* -type f -name '*pyc'-delete; find ~/local/lib/python3/cmk_addons/plugins/* -type d -empty -delete; omd restart apache; omd restart redis; cmk -O; cmk -R

I also don’t know if there are better options to use. All I know is it seems to work for me.

Sorry for hijacking this channel but I’m running into the similar issue. I use some “own-developed” plugins which worked fine under CMK 2.3.0. After migrating the plugins and upgrade CMK to 2.4.0 I get the same error.
I followed your workaround solution and now the plugins/services are monitored correctly in Web-UI. Nevertheless the Check_MK Discovery service shows vanished services belonging to the plugins and when I run a service discovery over Web-UI the service shows Unknown state and “Unimplemented check” again. If I check via CLI there are no errors and everything is monitored properly.

Is there any other guess on how to solve the issue or did I miss something on the new Plugin API?

BR

Hi,

After correcting the plugins and useing the API v2.
I corrected the problem by completly rebooting the omd like so :

omd restart

After that everything went back to normal

Hi,
thanks for your reply. The complete restart worked partially. When I do a service discovery over Web-GUI now the plugin services don’t vanish and they don’t have an Unknown state. Nevertheless the Check_MK Discovery service summary still states vanished services.

I guess I will leave it like that und wait for some future updates.

BR

Hi!

If you looked into all the docs on the new DevAPIs and still have issues, I would like to invite you to our DevHour that we will have on the 28th of May: DevHour: Q&A on Plug-in Migration

One of the Checkmk developers would be answering questions about migrating plug-ins to 2.4, which seems to be the case here.

1 Like