Trying to get logic honor if-statements to control output

Hi all,

As i am quite new to this type of development/fiddling around with check-plugins first of all if i am asking in a wrong wat, please correct me.

Now the case :

I have a client-script that should output updates as found via DND package-manager :

#!/bin/sh

CMK_VERSION="2.0.0p11"

DO_UPDATE=yes

echo '<<<linux_dnf>>>'
function check_dnf_updates {
    if [ "$DO_UPDATE" = yes ] ; then
        /usr/bin/dnf makecache 2> /dev/null
    fi
    /usr/bin/dnf updateinfo
}

#if command -v dnf &> /dev/null; then
#    echo "<<<linux_dnf>>>"
#    echo "5 Security notice(s)"
#    echo "1 Bugfix notice(s)"
#    echo "8 Enhancement notice(s)"
#    echo "3 other notice(s)"
#fi

    output=$(check_dnf_updates)
    if echo $output | grep -q "Updates Information Summary: available"; then
        echo $output | grep -o "[[:digit:]]\+\sBugfix"
        echo $output | grep -o "[[:digit:]]\+\sSecurity"
        echo $output | grep -o "[[:digit:]]\+\sModerate"
        echo $output | grep -o "[[:digit:]]\+\sLow"
        echo $output | grep -o "[[:digit:]]\+\sEnhancement"
        echo $output | grep -o "[[:digit:]]\+\sother"
    else
        echo "No updates found"
    fi

So in essence this should deliver a/the correct format to the CMK server for interpretation.

On the Server i have been struggling to get the plugin to evaluate the offerd data.

from .agent_based_api.v1 import *

def discover_linux_dnf(section):
    yield Service()

def check_linux_dnf(section):
    for line in section:
        if line[0].isdigit():
            if line[0].find('Bugfix'):
                yield Result(state=State.WARN, summary=line[0] + " Bugfix Updates")

            if ("Enhancement" in line[0] != True):
                yield Result(state=State.WARN, summary=line[0] + " Enhancement Updates")

            if "Security" in line[0]:
                yield Result(state=State.CRIT, summary=line[0] + " Security Updates")

        return
    yield Result(state=State.OK, summary="No DNF Updates found.")

register.check_plugin(
    name="linux_dnf",
    service_name="DNF Updates",
    discovery_function=discover_linux_dnf,
    check_function=check_linux_dnf,
)

Now from what i can tell :

  • the expected ( if any) numeric will corectly engage the further conditions.
  • The further conditions however do NOT honor any means of != -1 ( which should be the output of a find condition.
  • Also the (as above) looking for a textual match via the in method does not give expected result conditions.

So what am i missing here ?

i am sort-of stuck in this.

  • Glowsome

I cannot help you on the programming part - others might though - but if you only want to get the job done, this plugin from our exchange handles YUM/DNF based systems.
If this is merely a training exercise, I am sure someone can give you pointers. :slight_smile:

Well its 2-fold.

On the one end iā€™d like to get this monitored.
But on the other hand iā€™m also after learning the way in which plugins are made (correctly).

iā€™ve been over and over the docs, but i seem to be missing the just that part that makes the whole puzzle fall into place.

  • Glowsome

This will not work, see comments inline

if line[0].isdigit():  # this checks for a number
            if line[0].find('Bugfix'):  # if it is a number it can not contain a string
                .....
            if ("Enhancement" in line[0] != True):  # can also not contain a string
               .....
            if "Security" in line[0]:  # and again can not contain a string
               ....

Ok, iā€™ve been fiddling around a bit as to the feedback/comment @thl-cmk has made.

So i changed the

if line[0].isdigit():  # this checks for a number

to

if (line[0][0].isdigit()): # this should (only) check the _first_character of the line is a number

From my point of view this should be the corect criteria to move further down the logic.
However if i were to make a line after this

yield Result(state=State.WARN, summary=line[0])
return

I only see the digit back ā€¦ not the entire line - which i would expect.
It is as if the content of line[0] is replaced with the outcome of the evaluation.

  • Glowsome

asumming from your output, the check section sould look like this

[
 ['5', 'Security', 'notice(s)'], 
 ['1', 'Bugfix', 'notice(s)'], 
 ['8', 'Enhancement', 'notice(s)'], 
 ['3', 'other', 'notice(s)']
]

if this is correct, there is no real need to first check for a digit at the start of the line, you can easyly check if line[1] contains the string you are looking for, and if so yield your check state with line[0] as the value.

def check_linux_dnf(section):
    for line in section:
        if line[1] == 'Bugfix':
            yield Result(state=State.WARN, summary=line[0] + " Bugfix Updates")
        elif line[1] == "Enhancement":
            yield Result(state=State.WARN, summary=line[0] + " Enhancement Updates")
        elif line[0] == "Security":
            yield Result(state=State.CRIT, summary=line[0] + " Security Updates")
        return
    yield Result(state=State.OK, summary="No DNF Updates found.")

if you still want to check if line[0] is a digit you can do this like so:

def check_linux_dnf(section):
    for line in section:
        if line[0].isdigit:
            if line[1] == 'Bugfix':
                yield Result(state=State.WARN, summary=line[0] + " Bugfix Updates")
            elif line[1] == "Enhancement":
                yield Result(state=State.WARN, summary=line[0] + " Enhancement Updates")
            elif line[1] == "Security":
                yield Result(state=State.CRIT, summary=line[0] + " Security Updates")
            return
    yield Result(state=State.OK, summary="No DNF Updates found.")

btw. have a look at the Writing your own check plug-ins. There you will also find some basic steps on how to debug your checks.

1 Like

@thl-cmk In reply to your postā€¦ for a part you are correct as to the input. ( the client bash script was included in the original post)

However due to the nature of updates i cannot tell in advance if a category is present in the output.

So in this the status would need to reflect OK when there are no numbers present in the output ( the output of the client-script will just read "ā€œNo updates foundā€

So my way of handling this is to report (return) state.OK immediately, not evaluating further logic.

IF however the evaluation does return true on having a number, then further evaluation is needed as to how many, and what type of update is available.

So in your example i cannot tell if line contains either ā€˜Bugfix, Enhancement, Securityā€™ or even how many lines my output has.
Therefore i am searching for a way to loop over all presented to the server, and in the end have a cumulative state and multiple line summary.

For your insight as to the summary i am looking for as example when multiple categories of updates are available:

3 Bugfix Update(s) [WARN],
2 Enhancement Update(s) [WARN],
1 Security Update(s) [CRIT]

Calculating a total status of the service as [CRIT]

ā€¦ and yes i have been reading the referenced ā€œWriting your own check plug-insā€ over and over again :slight_smile:

  • Glowsome

You can try it like this

def check_linux_dnf(section):
    update_found=False  # init  update_found marker 
    for line in section:  # loop over the lines
        if line[0].isdigit:  # check if number (update found)
            update_found=True  # set marker
            # check for the update type and output the result
            if line[1] == 'Bugfix':  
                yield Result(state=State.WARN, summary=line[0] + " Bugfix Updates")
            elif line[1] == "Enhancement":
                yield Result(state=State.WARN, summary=line[0] + " Enhancement Updates")
            elif line[1] == "Security":
                yield Result(state=State.CRIT, summary=line[0] + " Security Updates")
    # if no update found, outpout a summary
    if not update_found:  
        yield Result(state=State.OK, summary="No DNF Updates found.")