I needed a quick and dirty check for the pfSense’s "State Table" via SNMP as I sometimes have the strange problem that it gets full and then I lose internet-connection. If the thresholds are hit and I am alerted, I hope I have time to investigate what is going wrong.

The Check

The default values for the searches is much too low – you can set it by a rule later to about 1000000/2000000. Perfdata graphs can be optionally turned on or off.

#!/usr/bin/env python
#
# Copyright 2020, Clemens Steinkogler <c.steinkogler[at]steinkogler.org>
#
# This program 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, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# pfStateTable          .1.3.6.1.4.1.12325.1.200.1.3
# pfStateTableCount     .1.3.6.1.4.1.12325.1.200.1.3.1
# pfStateTableSearches  .1.3.6.1.4.1.12325.1.200.1.3.2
# pfStateTableInserts   .1.3.6.1.4.1.12325.1.200.1.3.3
# pfStateTableRemovals  .1.3.6.1.4.1.12325.1.200.1.3.4

from pprint import pprint

# factory_settings ... is part of version/share/check_mk/modules/check_mk.py
# ((warn, crit), perfdata)
factory_settings["check_pfsense_state_table_default_values"] = {
    'config': ((10000, 20000), False)
}

def inventory_check_pfsense_state_table(info):
    # debug
    # print(info[0])
    # we check for 4 values
    if len(info[0]) == 4:
        # return the different tablestates-names with warn/crit tuples set to None
        return (
                ("count", "check_pfsense_state_table_default_values"),
                ("searches", "check_pfsense_state_table_default_values"),
                ("inserts", "check_pfsense_state_table_default_values"),
                ("removals", "check_pfsense_state_table_default_values")
               )
    # endif
# enddef

def check_pfsense_state_table(item, params, info):
    state = 0
    check_state_output = []
    perfdata = None
    # debug
    #print(item)
    #pprint(params)

    # value_type can be "gauge" (default) or "counter"
    def check_state(item_name, item_value, item_params, value_type="gauge"):
        item_value = int(item_value)
        diff_item_value = 0
        item_warn_value = item_params['config'][0][0]
        item_crit_value = item_params['config'][0][1]
        item_perfdata_switch = item_params['config'][1]
        # debug
        #print(value_type)

        if value_type == "gauge":
            # debug
            #pprint(item_params)
            #pprint(item_warn_value)
            #pprint(item_crit_value)
            #pprint(item_perfdata_switch)

            if item_perfdata_switch:
                perfdata_part = [(item_name, item_value, item_warn_value, item_crit_value)]
            else:
                perfdata_part = None
            # endif
        else:
            # * we get the last value from the counter-file if possible into var last_counter_value
            #  * else we save it in counter-file and return no perfdata
            # * if new value is smaller than old value, the firewall must have been reset, we add the current value to last one
            # * if new value is larger than old value, we calculate the difference between them
            # * at the end we save the current value
            first_value = False
            last_counter_value = get_item_state(item_name)

            if last_counter_value is None:
                set_item_state(item_name, item_value)
                first_value = True
                perfdata_part = None
            else:        
                # debug
                #pprint(last_counter_value)

                if item_value < last_counter_value:
                    diff_item_value = item_value + last_counter_value
                else:
                    diff_item_value = item_value - last_counter_value
                # endif

                set_item_state(item_name, item_value)

                # we replace the real item_value with the calculated difference
                item_value = diff_item_value
                # debug
                #print(perfdata_part)
            # endif

            if item_perfdata_switch:
                if not first_value:
                    perfdata_part = [(item_name, diff_item_value, item_warn_value, item_crit_value)]
            else:
                perfdata_part = None
            # endif
        # endif

        if item_value >= item_crit_value:
            state = 2
        elif item_warn_value <= item_value < item_crit_value:
            state = 1
        elif item_value < item_warn_value:
            state = 0
        else:
            state = 3
        # endif

        if state == 0:
            message_part = "%s %d %s" % (item_name, item_value, "(.)")
        elif state == 1:
            message_part = "%s %d %s" % (item_name, item_value, "(!)")
        elif state == 2:
            message_part = "%s %d %s" % (item_name, item_value, "(!!)")
        else:
            message_part = "%s %d %s" % (item_name, item_value, "(?)")
        # endif

        # debug
        #print(message_part)
        return state, message_part, perfdata_part
    # enddef

    if len(info[0]) == 4:
        info_i = {"count": 0, "searches": 1, "inserts": 2, "removals": 3}

        if item == "count":
            check_state_output = check_state(item, info[0][info_i[item]], params, "gauge")
        else:
            check_state_output = check_state(item, info[0][info_i[item]], params, "counter")
        # endif
    # endif

    # debug
    #print(check_state_output[1])
    state = check_state_output[0]
    message = check_state_output[1]
    perfdata = check_state_output[2]

    return state, message, perfdata
# enddef

check_info["check_pfsense_state_table"] = {
    "has_perfdata": True,
    "default_levels_variable": "check_pfsense_state_table_default_values",
    "group": "check_pfsense_state_table",
    "check_function": check_pfsense_state_table,
    "inventory_function": inventory_check_pfsense_state_table,
    "service_description": "pfSense StateTable",
    "snmp_info": (".1.3.6.1.4.1.12325.1.200.1.3", ["1", "2", "3", "4"])
}

The WATO-Parameters Config

# Copyright 2020, Clemens Steinkogler <c.steinkogler[at]steinkogler.org>
#
# This program 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, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

group = "checkparams"

subgroup_applications = _("Applications, Processes & Services")

register_check_parameters(
    subgroup_applications,
    "check_pfsense_state_table",
    _("pfSense State Table Levels"),
    Dictionary(
        elements=[
            ("config",
                Tuple(
                    title=_("Config for Service"),
                    elements=[
                        Optional(
                            Tuple(
                                elements=[
                                    Integer(
                                        title=_("Warning Level"),
                                        default_value=10000
                                    ),
                                    Integer(
                                        title=_("Critical Level"),
                                        default_value=20000
                                    ),
                                ]
                            ),
                            label=_("Warn-/Crit-Levels"),
                            none_label=_("Using default values"),
                            none_value=(10000, 20000)
                        ),
                        DropdownChoice(
                            title=_("Create graph"),
                            choices=[
                                (False, _("No")),
                                (True, _("Yes")),
                            ],
                            default_value=False
                        ),
                    ]
                ),
            ),
        ]
    ),
    TextAscii(
        title=_("Service description"),
        allow_empty=False,
    ),
    "dict"
)

Screenshots

Zuletzt bearbeitet: Februar 15, 2021

Autor

Kommentare

Kommentar verfassen

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.