From 75dc9c995bf2c0a720af5cd9c3e918c2e3e28039 Mon Sep 17 00:00:00 2001 From: "Th.L" <thl-cmk@outlook.com> Date: Thu, 25 Mar 2021 14:50:19 +0100 Subject: [PATCH] update project --- agent_based/cisco_asyncos_bandwidth.py | 22 +- agent_based/cisco_asyncos_license.py | 10 +- agent_based/cisco_asyncos_update.py | 312 +++++++++++++++++++++++ checks/cisco_asyncos_update | 259 ------------------- cisco_asyncos.mkp | Bin 11974 -> 11591 bytes packages/cisco_asyncos | 4 +- web/plugins/wato/cisco_asyncos_queue.py | 58 +++-- web/plugins/wato/cisco_asyncos_update.py | 74 ++++-- 8 files changed, 424 insertions(+), 315 deletions(-) create mode 100644 agent_based/cisco_asyncos_update.py delete mode 100644 checks/cisco_asyncos_update diff --git a/agent_based/cisco_asyncos_bandwidth.py b/agent_based/cisco_asyncos_bandwidth.py index 0b6374c..6fdcc67 100644 --- a/agent_based/cisco_asyncos_bandwidth.py +++ b/agent_based/cisco_asyncos_bandwidth.py @@ -51,16 +51,32 @@ def discovery_cisco_asyncos_bandwidth(section: CiscoAsyncosBandwidth) -> Discove def check_cisco_asyncos_bandwidth(params, section: CiscoAsyncosBandwidth) -> CheckResult: yield from check_levels( - section.bandwidth_now, + section.bandwidth_now * 8, label='Current bandwidth', levels_upper=params.get('upper', None), levels_lower=params.get('lower', None), metric_name='bandwith_now', + render_func=render.networkbandwidth, + unit='bits/s' + ) + yield from check_levels( + section.bandwidth_hour * 8, + label='last hour', + # levels_upper=params.get('upper', None), + # levels_lower=params.get('lower', None), + # metric_name='bandwith_now', + render_func=render.networkbandwidth + ) + yield from check_levels( + section.bandwidth_day * 8, + label='last day', + #levels_upper=params.get('upper', None), + #levels_lower=params.get('lower', None), + #metric_name='bandwith_now', render_func=render.networkbandwidth ) - yield Result(state=State.OK, - summary='last hour: %s, last day: %s' % (section.bandwidth_hour, section.bandwidth_day)) + # yield Result(state=State.OK, summary='last hour: %s, last day: %s' % (section.bandwidth_hour, section.bandwidth_day)) register.snmp_section( diff --git a/agent_based/cisco_asyncos_license.py b/agent_based/cisco_asyncos_license.py index 3d8bc5a..91f8e42 100644 --- a/agent_based/cisco_asyncos_license.py +++ b/agent_based/cisco_asyncos_license.py @@ -185,6 +185,7 @@ def parse_cisco_asyncos_license(string_table: List[StringTable]) -> Mapping[str, def discovery_cisco_asyncos_license(section: Mapping[str, CiscoAsyncosLicense]) -> DiscoveryResult: yield Service() + # Parameters({'expire': (400, 360), 'features_ignore': ['Data Loss Prevention']}) def check_cisco_asyncos_license(params, section: Mapping[str, CiscoAsyncosLicense]) -> CheckResult: features_ignore = params.get('features_ignore', []) @@ -194,10 +195,11 @@ def check_cisco_asyncos_license(params, section: Mapping[str, CiscoAsyncosLicens if section[license].perpetual: yield Result(state=State.OK, notice='%s is perpetual (will not expire)' % license) elif license in features_ignore: - yield Result(state=State.OK, notice='%s will expire at %s (%s days). Feature ignored!' % (license, section[license].expiredate, section[license].daysuntilexpire)) + yield Result(state=State.OK, notice='%s will expire at %s (%s days). Feature ignored!' % ( + license, section[license].expiredate, section[license].daysuntilexpire)) ignore_count += 1 elif section[license].secondsuntilexpire == 0: - yield Result(state=State.CRIT, notice='%s has expired or is not licensed' % license) + yield Result(state=State.CRIT, notice='%s has expired or is not licensed' % license) else: if section[license].daysuntilexpire < crit: state = State.CRIT @@ -206,10 +208,12 @@ def check_cisco_asyncos_license(params, section: Mapping[str, CiscoAsyncosLicens else: state = State.OK - yield Result(state=state, notice='%s will expire at %s (%s days)' % (license, section[license].expiredate, section[license].daysuntilexpire)) + yield Result(state=state, notice='%s will expire at %s (%s days)' % ( + license, section[license].expiredate, section[license].daysuntilexpire)) yield Result(state=State.OK, summary='%d/%d Features found/ignored' % (len(section.keys()), ignore_count)) + register.snmp_section( name='cisco_asyncos_license', parse_function=parse_cisco_asyncos_license, diff --git a/agent_based/cisco_asyncos_update.py b/agent_based/cisco_asyncos_update.py new file mode 100644 index 0000000..3e18099 --- /dev/null +++ b/agent_based/cisco_asyncos_update.py @@ -0,0 +1,312 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# License: GNU General Public License v2 +# +# Author: thl-cmk[at]outlook[dot]com +# URL : https://thl-cmk.hopto.org +# Date : 2020-02-19 +# +# 2020-05-14: added wato oprion to ignore items +# 2021-03-25: rewrite for CMK2.0 +# +# +# sample snmpwalk +# +# OMD[cmk16x]:~$ snmpwalk -v2c -c public -m ASYNCOS-MAIL-MIB -ObentU localhost updateEntry +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.1 = INTEGER: 1 +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.2 = INTEGER: 2 +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.3 = INTEGER: 3 +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.4 = INTEGER: 4 +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.5 = INTEGER: 5 +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.6 = INTEGER: 6 +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.7 = INTEGER: 7 +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.8 = INTEGER: 8 +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.9 = INTEGER: 9 +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.10 = INTEGER: 10 +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.11 = INTEGER: 11 +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.12 = INTEGER: 12 +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.13 = INTEGER: 13 +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.14 = INTEGER: 14 +# .1.3.6.1.4.1.15497.1.1.1.13.1.1.15 = INTEGER: 15 +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.1 = STRING: File Reputation +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.2 = STRING: IronPort Anti-Spam +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.3 = STRING: McAfee +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.4 = STRING: Sophos Anti-Virus +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.5 = STRING: amp +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.6 = STRING: content_scanner +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.7 = STRING: enrollment_client +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.8 = STRING: geo_countries +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.9 = STRING: howto +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.10 = STRING: openssh_key +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.11 = STRING: repeng +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.12 = STRING: sdr_client +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.13 = STRING: smart_agent +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.14 = STRING: support_request +# .1.3.6.1.4.1.15497.1.1.1.13.1.2.15 = STRING: timezones +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.1 = Counter32: 1 +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.2 = Counter32: 10 +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.3 = Counter32: 1 +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.4 = Counter32: 1 +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.5 = Counter32: 1 +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.6 = Counter32: 1 +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.7 = Counter32: 1 +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.8 = Counter32: 1 +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.9 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.10 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.11 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.12 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.13 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.14 = Counter32: 1 +# .1.3.6.1.4.1.15497.1.1.1.13.1.3.15 = Counter32: 1 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.1 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.2 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.3 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.4 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.5 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.6 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.7 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.8 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.9 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.10 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.11 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.12 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.13 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.14 = Counter32: 0 +# .1.3.6.1.4.1.15497.1.1.1.13.1.4.15 = Counter32: 0 +# +# OMD[cmk16x]:~$ snmpwalk -v2c -c public -m ASYNCOS-MAIL-MIB localhost updateEntry +# ASYNCOS-MAIL-MIB::updateIndex.1 = INTEGER: 1 +# ASYNCOS-MAIL-MIB::updateIndex.2 = INTEGER: 2 +# ASYNCOS-MAIL-MIB::updateIndex.3 = INTEGER: 3 +# ASYNCOS-MAIL-MIB::updateIndex.4 = INTEGER: 4 +# ASYNCOS-MAIL-MIB::updateIndex.5 = INTEGER: 5 +# ASYNCOS-MAIL-MIB::updateIndex.6 = INTEGER: 6 +# ASYNCOS-MAIL-MIB::updateIndex.7 = INTEGER: 7 +# ASYNCOS-MAIL-MIB::updateIndex.8 = INTEGER: 8 +# ASYNCOS-MAIL-MIB::updateIndex.9 = INTEGER: 9 +# ASYNCOS-MAIL-MIB::updateIndex.10 = INTEGER: 10 +# ASYNCOS-MAIL-MIB::updateIndex.11 = INTEGER: 11 +# ASYNCOS-MAIL-MIB::updateIndex.12 = INTEGER: 12 +# ASYNCOS-MAIL-MIB::updateIndex.13 = INTEGER: 13 +# ASYNCOS-MAIL-MIB::updateIndex.14 = INTEGER: 14 +# ASYNCOS-MAIL-MIB::updateIndex.15 = INTEGER: 15 +# ASYNCOS-MAIL-MIB::updateServiceName.1 = STRING: File Reputation +# ASYNCOS-MAIL-MIB::updateServiceName.2 = STRING: IronPort Anti-Spam +# ASYNCOS-MAIL-MIB::updateServiceName.3 = STRING: McAfee +# ASYNCOS-MAIL-MIB::updateServiceName.4 = STRING: Sophos Anti-Virus +# ASYNCOS-MAIL-MIB::updateServiceName.5 = STRING: amp +# ASYNCOS-MAIL-MIB::updateServiceName.6 = STRING: content_scanner +# ASYNCOS-MAIL-MIB::updateServiceName.7 = STRING: enrollment_client +# ASYNCOS-MAIL-MIB::updateServiceName.8 = STRING: geo_countries +# ASYNCOS-MAIL-MIB::updateServiceName.9 = STRING: howto +# ASYNCOS-MAIL-MIB::updateServiceName.10 = STRING: openssh_key +# ASYNCOS-MAIL-MIB::updateServiceName.11 = STRING: repeng +# ASYNCOS-MAIL-MIB::updateServiceName.12 = STRING: sdr_client +# ASYNCOS-MAIL-MIB::updateServiceName.13 = STRING: smart_agent +# ASYNCOS-MAIL-MIB::updateServiceName.14 = STRING: support_request +# ASYNCOS-MAIL-MIB::updateServiceName.15 = STRING: timezones +# ASYNCOS-MAIL-MIB::updates.1 = Counter32: 1 +# ASYNCOS-MAIL-MIB::updates.2 = Counter32: 10 +# ASYNCOS-MAIL-MIB::updates.3 = Counter32: 1 +# ASYNCOS-MAIL-MIB::updates.4 = Counter32: 1 +# ASYNCOS-MAIL-MIB::updates.5 = Counter32: 1 +# ASYNCOS-MAIL-MIB::updates.6 = Counter32: 1 +# ASYNCOS-MAIL-MIB::updates.7 = Counter32: 1 +# ASYNCOS-MAIL-MIB::updates.8 = Counter32: 1 +# ASYNCOS-MAIL-MIB::updates.9 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updates.10 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updates.11 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updates.12 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updates.13 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updates.14 = Counter32: 1 +# ASYNCOS-MAIL-MIB::updates.15 = Counter32: 1 +# ASYNCOS-MAIL-MIB::updateFailures.1 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updateFailures.2 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updateFailures.3 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updateFailures.4 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updateFailures.5 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updateFailures.6 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updateFailures.7 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updateFailures.8 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updateFailures.9 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updateFailures.10 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updateFailures.11 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updateFailures.12 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updateFailures.13 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updateFailures.14 = Counter32: 0 +# ASYNCOS-MAIL-MIB::updateFailures.15 = Counter32: 0 +# +from typing import Mapping, List, NamedTuple + +from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( + DiscoveryResult, + CheckResult, + StringTable, +) + +from cmk.base.plugins.agent_based.agent_based_api.v1 import ( + register, + Service, + check_levels, + Result, + SNMPTree, + contains, + State, + render, +) + + +class CiscoAsyncosUpdate(NamedTuple): + updates: int + updatefailures: int + +# [[ +# ['File Reputation', '6', '38'], +# ['IronPort Anti-Spam', '12', '9'], +# ['McAfee', '6', '25'], +# ['Sophos Anti-Virus', '6', '17'], +# ['amp', '1', '0'], +# ['content_scanner', '1', '0'], +# ['enrollment_client', '1', '0'], +# ['geo_countries', '1', '0'], +# ['howto', '0', '0'], +# ['openssh_key', '0', '0'], +# ['repeng', '0', '0'], +# ['sdr_client', '0', '0'], +# ['smart_agent', '0', '0'], +# ['support_request', '1', '0'], +# ['timezones', '1', '0'] +# ]] +def parse_cisco_asyncos_update(string_table: List[StringTable]) -> Mapping[str, CiscoAsyncosUpdate]: + features = {} + for feature, updates, update_failures in string_table[0]: + features.update({feature: CiscoAsyncosUpdate( + updates=int(updates), + updatefailures=int(update_failures) + ) }) + return features + +# { +# 'File Reputation': CiscoAsyncosUpdate(updates=6, updatefailures=38), +# 'IronPort Anti-Spam': CiscoAsyncosUpdate(updates=12, updatefailures=9), +# 'McAfee': CiscoAsyncosUpdate(updates=6, updatefailures=25), +# 'Sophos Anti-Virus': CiscoAsyncosUpdate(updates=6, updatefailures=17), +# 'amp': CiscoAsyncosUpdate(updates=1, updatefailures=0), +# 'content_scanner': CiscoAsyncosUpdate(updates=1, updatefailures=0), +# 'enrollment_client': CiscoAsyncosUpdate(updates=1, updatefailures=0), +# 'geo_countries': CiscoAsyncosUpdate(updates=1, updatefailures=0), +# 'howto': CiscoAsyncosUpdate(updates=0, updatefailures=0), +# 'openssh_key': CiscoAsyncosUpdate(updates=0, updatefailures=0), +# 'repeng': CiscoAsyncosUpdate(updates=0, updatefailures=0), +# 'sdr_client': CiscoAsyncosUpdate(updates=0, updatefailures=0), +# 'smart_agent': CiscoAsyncosUpdate(updates=0, updatefailures=0), +# 'support_request': CiscoAsyncosUpdate(updates=1, updatefailures=0), +# 'timezones': CiscoAsyncosUpdate(updates=1, updatefailures=0) +# } +def discovery_cisco_asyncos_update(section:Mapping[str, CiscoAsyncosUpdate])-> DiscoveryResult: + yield Service() + +def check_cisco_asyncos_update(params, section:Mapping[str, CiscoAsyncosUpdate]) -> CheckResult: + features_ignore = params.get('features_ignore', []) + warn, crit = params.get('failedLevel') + ignore_count = 0 + for feature in section.keys(): + if feature in features_ignore: + yield Result(state=State.OK, notice='Feature %s: %d/%d updates/update failures. Feature ignored!' % (feature, section[feature].updates, section[feature].updatefailures)) + ignore_count += 1 + else: + yield Result(state=State.OK, notice='Feature %s: %d/%d updates/update failures. Feature ignored!' % (feature, section[feature].updates, section[feature].updatefailures)) + + yield Result(state=State.OK, summary='%d/%d Features found/ignored' % (len(section.keys()), ignore_count)) + + # if len(info) > 0: + # infotext = '' + # longoutput = '' + # perfdata = [] + # failedItemsWarn = [] + # failedItemsCrit = [] + # failedWarn, failedCrit = params.get('failedLevel') + # features_ignore = params['features_ignore'] + # lastState = 1 + # + # for line in info: + # name, passed, failed = line + # longoutput += '\n%s: %s/%s passed/failed attempt(s)' % (name, passed, failed) + # # read counters + # passedLast = get_item_state('cisco_asyncos_update_%s_passedLast' % name) + # failedLast = get_item_state('cisco_asyncos_update_%s_failedLast' % name) + # failedAttempts = get_item_state('cisco_asyncos_update_%s_failedAttempts' % name) + # + # if (passedLast == None) or (failedLast == None) or (failedAttempts == None): # or (lastState == None): + # # init counters + # set_item_state('cisco_asyncos_update_%s_passedLast' % name, passed) + # set_item_state('cisco_asyncos_update_%s_failedLast' % name, failed) + # set_item_state('cisco_asyncos_update_%s_failedAttempts' % name, 0) + # else: + # set_item_state('cisco_asyncos_update_%s_passedLast' % name, passed) + # set_item_state('cisco_asyncos_update_%s_failedLast' % name, failed) + # passedLast = int(passedLast) + # failedLast = int(failedLast) + # failedAttempts = int(failedAttempts) + # failed = int(failed) + # passed = int(passed) + # # reset counter if overrun + # if failed < failedLast: + # set_item_state('cisco_asyncos_update_%s_failedLast' % name, failed) + # failedLast = failed + # if passed < passedLast: + # set_item_state('cisco_asyncos_update_%s_passedLast' % name, passed) + # passedLast = passed + # + # if passed > passedLast: + # # rest error counter after passed update attempt + # set_item_state('cisco_asyncos_update_%s_failedAttempts' % name, 0) + # else: + # failedAttempts = failedAttempts + failed - failedLast + # set_item_state('cisco_asyncos_update_%s_failedAttempts' % name, failedAttempts) + # if name not in features_ignore: + # if failedAttempts >= failedCrit: + # failedItemsCrit.append(name) + # lastState = -1 + # elif failedAttempts >= failedWarn: + # failedItemsWarn.append(name) + # lastState = -1 + # + # perfdata.append((name.replace(' ', '_'), lastState, None, None, -1, 1)) + # + # infotext += '%d item(s) found' % len(info) + # if len(failedItemsCrit) > 0: + # yield 2, '%d failed item(s) (%s), failed attempts >= %d' % (len(failedItemsCrit), ', '.join(failedItemsCrit), failedCrit) + # if len(failedItemsWarn) > 0: + # yield 1, '%d failed item(s) (%s), failed attempts >= %d' % (len(failedItemsWarn), ', '.join(failedItemsWarn), failedWarn) + # + # yield 0, infotext + longoutput, perfdata + + + +register.snmp_section( + name='cisco_asyncos_update', + parse_function=parse_cisco_asyncos_update, + fetch=[ + SNMPTree( + base='.1.3.6.1.4.1.15497.1.1.1.13.1', # ASYNCOS-MAIL-MIB::updateEntry + oids=[ + '2', # updateServiceName -> A textual name for an update entry + '3', # updates -> The number of successful attempts that have occurred when updating a service + '4', # updateFailures -> "The number of failed attempts that have occurred when updating a service + ] + ), + ], + detect=contains('.1.3.6.1.2.1.1.1.0', 'AsyncOS'), +) + +register.check_plugin( + name='cisco_asyncos_update', + service_name='Update', + discovery_function=discovery_cisco_asyncos_update, + check_function=check_cisco_asyncos_update, + check_default_parameters={'failedLevel': (5, 10)}, + check_ruleset_name='cisco_asyncos_update', +) + diff --git a/checks/cisco_asyncos_update b/checks/cisco_asyncos_update deleted file mode 100644 index 333795a..0000000 --- a/checks/cisco_asyncos_update +++ /dev/null @@ -1,259 +0,0 @@ -#!/usr/bin/python -# -*- encoding: utf-8; py-indent-offset: 4 -*- -# -# Rewriten by: Th.L. -# Date: 19-02-2020 -# -# 2020-05-14: added wato oprion to ignore items -# -# check_mk 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 in version 2. check_mk is distributed -# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with- -# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. See the GNU General Public License for more de- -# ails. You should have received a copy of the GNU General Public -# License along with GNU Make; see the file COPYING. If not, write -# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, -# Boston, MA 02110-1301 USA. -# -# -# sample snmpwalk -# -# OMD[cmk16x]:~$ snmpwalk -v2c -c public -m ASYNCOS-MAIL-MIB -ObentU localhost updateEntry -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.1 = INTEGER: 1 -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.2 = INTEGER: 2 -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.3 = INTEGER: 3 -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.4 = INTEGER: 4 -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.5 = INTEGER: 5 -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.6 = INTEGER: 6 -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.7 = INTEGER: 7 -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.8 = INTEGER: 8 -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.9 = INTEGER: 9 -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.10 = INTEGER: 10 -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.11 = INTEGER: 11 -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.12 = INTEGER: 12 -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.13 = INTEGER: 13 -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.14 = INTEGER: 14 -# .1.3.6.1.4.1.15497.1.1.1.13.1.1.15 = INTEGER: 15 -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.1 = STRING: File Reputation -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.2 = STRING: IronPort Anti-Spam -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.3 = STRING: McAfee -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.4 = STRING: Sophos Anti-Virus -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.5 = STRING: amp -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.6 = STRING: content_scanner -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.7 = STRING: enrollment_client -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.8 = STRING: geo_countries -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.9 = STRING: howto -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.10 = STRING: openssh_key -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.11 = STRING: repeng -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.12 = STRING: sdr_client -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.13 = STRING: smart_agent -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.14 = STRING: support_request -# .1.3.6.1.4.1.15497.1.1.1.13.1.2.15 = STRING: timezones -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.1 = Counter32: 1 -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.2 = Counter32: 10 -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.3 = Counter32: 1 -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.4 = Counter32: 1 -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.5 = Counter32: 1 -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.6 = Counter32: 1 -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.7 = Counter32: 1 -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.8 = Counter32: 1 -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.9 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.10 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.11 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.12 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.13 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.14 = Counter32: 1 -# .1.3.6.1.4.1.15497.1.1.1.13.1.3.15 = Counter32: 1 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.1 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.2 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.3 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.4 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.5 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.6 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.7 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.8 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.9 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.10 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.11 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.12 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.13 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.14 = Counter32: 0 -# .1.3.6.1.4.1.15497.1.1.1.13.1.4.15 = Counter32: 0 -# -# OMD[cmk16x]:~$ snmpwalk -v2c -c public -m ASYNCOS-MAIL-MIB localhost updateEntry -# ASYNCOS-MAIL-MIB::updateIndex.1 = INTEGER: 1 -# ASYNCOS-MAIL-MIB::updateIndex.2 = INTEGER: 2 -# ASYNCOS-MAIL-MIB::updateIndex.3 = INTEGER: 3 -# ASYNCOS-MAIL-MIB::updateIndex.4 = INTEGER: 4 -# ASYNCOS-MAIL-MIB::updateIndex.5 = INTEGER: 5 -# ASYNCOS-MAIL-MIB::updateIndex.6 = INTEGER: 6 -# ASYNCOS-MAIL-MIB::updateIndex.7 = INTEGER: 7 -# ASYNCOS-MAIL-MIB::updateIndex.8 = INTEGER: 8 -# ASYNCOS-MAIL-MIB::updateIndex.9 = INTEGER: 9 -# ASYNCOS-MAIL-MIB::updateIndex.10 = INTEGER: 10 -# ASYNCOS-MAIL-MIB::updateIndex.11 = INTEGER: 11 -# ASYNCOS-MAIL-MIB::updateIndex.12 = INTEGER: 12 -# ASYNCOS-MAIL-MIB::updateIndex.13 = INTEGER: 13 -# ASYNCOS-MAIL-MIB::updateIndex.14 = INTEGER: 14 -# ASYNCOS-MAIL-MIB::updateIndex.15 = INTEGER: 15 -# ASYNCOS-MAIL-MIB::updateServiceName.1 = STRING: File Reputation -# ASYNCOS-MAIL-MIB::updateServiceName.2 = STRING: IronPort Anti-Spam -# ASYNCOS-MAIL-MIB::updateServiceName.3 = STRING: McAfee -# ASYNCOS-MAIL-MIB::updateServiceName.4 = STRING: Sophos Anti-Virus -# ASYNCOS-MAIL-MIB::updateServiceName.5 = STRING: amp -# ASYNCOS-MAIL-MIB::updateServiceName.6 = STRING: content_scanner -# ASYNCOS-MAIL-MIB::updateServiceName.7 = STRING: enrollment_client -# ASYNCOS-MAIL-MIB::updateServiceName.8 = STRING: geo_countries -# ASYNCOS-MAIL-MIB::updateServiceName.9 = STRING: howto -# ASYNCOS-MAIL-MIB::updateServiceName.10 = STRING: openssh_key -# ASYNCOS-MAIL-MIB::updateServiceName.11 = STRING: repeng -# ASYNCOS-MAIL-MIB::updateServiceName.12 = STRING: sdr_client -# ASYNCOS-MAIL-MIB::updateServiceName.13 = STRING: smart_agent -# ASYNCOS-MAIL-MIB::updateServiceName.14 = STRING: support_request -# ASYNCOS-MAIL-MIB::updateServiceName.15 = STRING: timezones -# ASYNCOS-MAIL-MIB::updates.1 = Counter32: 1 -# ASYNCOS-MAIL-MIB::updates.2 = Counter32: 10 -# ASYNCOS-MAIL-MIB::updates.3 = Counter32: 1 -# ASYNCOS-MAIL-MIB::updates.4 = Counter32: 1 -# ASYNCOS-MAIL-MIB::updates.5 = Counter32: 1 -# ASYNCOS-MAIL-MIB::updates.6 = Counter32: 1 -# ASYNCOS-MAIL-MIB::updates.7 = Counter32: 1 -# ASYNCOS-MAIL-MIB::updates.8 = Counter32: 1 -# ASYNCOS-MAIL-MIB::updates.9 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updates.10 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updates.11 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updates.12 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updates.13 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updates.14 = Counter32: 1 -# ASYNCOS-MAIL-MIB::updates.15 = Counter32: 1 -# ASYNCOS-MAIL-MIB::updateFailures.1 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updateFailures.2 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updateFailures.3 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updateFailures.4 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updateFailures.5 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updateFailures.6 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updateFailures.7 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updateFailures.8 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updateFailures.9 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updateFailures.10 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updateFailures.11 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updateFailures.12 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updateFailures.13 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updateFailures.14 = Counter32: 0 -# ASYNCOS-MAIL-MIB::updateFailures.15 = Counter32: 0 -# -# sample info -# -# [[u'File Reputation', u'1', u'0'], -# [u'IronPort Anti-Spam', u'10', u'0'], -# [u'McAfee', u'1', u'0'], -# [u'Sophos Anti-Virus', u'1', u'0'], -# [u'amp', u'1', u'0'], -# [u'content_scanner', u'1', u'0'], -# [u'enrollment_client', u'1', u'0'], -# [u'geo_countries', u'1', u'0'], -# [u'howto', u'0', u'0'], -# [u'openssh_key', u'0', u'0'], -# [u'repeng', u'0', u'0'], -# [u'sdr_client', u'0', u'0'], -# [u'smart_agent', u'0', u'0'], -# [u'support_request', u'1', u'0'], -# [u'timezones', u'1', u'0'] -# ] -# - -factory_settings['cisco_asyncos_update_default_levels'] = { - 'failedLevel': (5, 10), - 'features_ignore': [] -} - - -def inventory_cisco_asyncos_update(info): - if len(info) > 0: - return [(None, None)] - - -def check_cisco_asyncos_update(_no_item, params, info): - if len(info) > 0: - infotext = '' - longoutput = '' - perfdata = [] - failedItemsWarn = [] - failedItemsCrit = [] - failedWarn, failedCrit = params.get('failedLevel') - features_ignore = params['features_ignore'] - lastState = 1 - - for line in info: - name, passed, failed = line - longoutput += '\n%s: %s/%s passed/failed attempt(s)' % (name, passed, failed) - # read counters - passedLast = get_item_state('cisco_asyncos_update_%s_passedLast' % name) - failedLast = get_item_state('cisco_asyncos_update_%s_failedLast' % name) - failedAttempts = get_item_state('cisco_asyncos_update_%s_failedAttempts' % name) - - if (passedLast == None) or (failedLast == None) or (failedAttempts == None): # or (lastState == None): - # init counters - set_item_state('cisco_asyncos_update_%s_passedLast' % name, passed) - set_item_state('cisco_asyncos_update_%s_failedLast' % name, failed) - set_item_state('cisco_asyncos_update_%s_failedAttempts' % name, 0) - else: - set_item_state('cisco_asyncos_update_%s_passedLast' % name, passed) - set_item_state('cisco_asyncos_update_%s_failedLast' % name, failed) - passedLast = int(passedLast) - failedLast = int(failedLast) - failedAttempts = int(failedAttempts) - failed = int(failed) - passed = int(passed) - # reset counter if overrun - if failed < failedLast: - set_item_state('cisco_asyncos_update_%s_failedLast' % name, failed) - failedLast = failed - if passed < passedLast: - set_item_state('cisco_asyncos_update_%s_passedLast' % name, passed) - passedLast = passed - - if passed > passedLast: - # rest error counter after passed update attempt - set_item_state('cisco_asyncos_update_%s_failedAttempts' % name, 0) - else: - failedAttempts = failedAttempts + failed - failedLast - set_item_state('cisco_asyncos_update_%s_failedAttempts' % name, failedAttempts) - if name not in features_ignore: - if failedAttempts >= failedCrit: - failedItemsCrit.append(name) - lastState = -1 - elif failedAttempts >= failedWarn: - failedItemsWarn.append(name) - lastState = -1 - - perfdata.append((name.replace(' ', '_'), lastState, None, None, -1, 1)) - - infotext += '%d item(s) found' % len(info) - if len(failedItemsCrit) > 0: - yield 2, '%d failed item(s) (%s), failed attempts >= %d' % (len(failedItemsCrit), ', '.join(failedItemsCrit), failedCrit) - if len(failedItemsWarn) > 0: - yield 1, '%d failed item(s) (%s), failed attempts >= %d' % (len(failedItemsWarn), ', '.join(failedItemsWarn), failedWarn) - - yield 0, infotext + longoutput, perfdata - - -check_info['cisco_asyncos_update'] = { - 'check_function': check_cisco_asyncos_update, - 'inventory_function': inventory_cisco_asyncos_update, - 'group': 'cisco_asyncos_update', - 'service_description': 'Update', - 'has_perfdata': True, - 'snmp_info': ('.1.3.6.1.4.1.15497.1.1.1.13.1', [ # ASYNCOS-MAIL-MIB::updateEntry - '2', # updateServiceName --> A textual name for an update entry - '3', # updates --> The number of successful attempts that have occurred when updating a service - '4', # updateFailures --> "The number of failed attempts that have occurred when updating a service - ]), - 'default_levels_variable': 'cisco_asyncos_update_default_levels', - 'snmp_scan_function': lambda oid: oid('.1.3.6.1.2.1.1.1.0').find('AsyncOS') != -1, - # 'snmp_scan_function': scan_cisco_asyncos, - # 'includes': ['cisco_asyncos.include'], -} - diff --git a/cisco_asyncos.mkp b/cisco_asyncos.mkp index 52a40594eff84cafd40e7eaa4496193b65e870ba..fa793cf65e90013d6fbb159691d48f2f33cc7338 100644 GIT binary patch literal 11591 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 RwT}>JUWX+js8(pG{{hOfF8}}l literal 11974 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 N0s=btU~S-F{}1Y?u4@1Q diff --git a/packages/cisco_asyncos b/packages/cisco_asyncos index 96321b6..0919172 100644 --- a/packages/cisco_asyncos +++ b/packages/cisco_asyncos @@ -37,8 +37,8 @@ 'cisco_asyncos_messageage.py', 'cisco_asyncos_queue.py', 'cisco_asyncos_resources.py', - 'cisco_asyncos_license.py'], - 'checks': ['cisco_asyncos_update'], + 'cisco_asyncos_license.py', + 'cisco_asyncos_update.py'], 'web': ['plugins/wato/cisco_asyncos_license.py', 'plugins/wato/cisco_asyncos_queue.py', 'plugins/wato/cisco_asyncos_update.py', diff --git a/web/plugins/wato/cisco_asyncos_queue.py b/web/plugins/wato/cisco_asyncos_queue.py index d3bf147..5b3722c 100644 --- a/web/plugins/wato/cisco_asyncos_queue.py +++ b/web/plugins/wato/cisco_asyncos_queue.py @@ -1,23 +1,41 @@ -#!/usr/bin/python -# -*- encoding: utf-8; py-indent-offset: 4 -*- +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- # # -register_check_parameters( - subgroup_applications, - 'cisco_asyncos_queue', - _('Cisco AsyncOS queue'), - Dictionary( - # help=_(''), - elements=[ - ('levels', - Tuple( - title=_('Levels for nuber of messages in work queue'), - elements=[ - Integer(title=_('Warning'), default_value=50, unit=_('# of messages')), - Integer(title=_('Critical'), default_value=100, unit=_('# of messages')), - ])), - ], - ), - None, - match_type='dict', +from cmk.gui.i18n import _ +from cmk.gui.valuespec import ( + Dictionary, + Integer, + TextAscii, + ListOfStrings, + Tuple, ) + +from cmk.gui.plugins.wato import ( + CheckParameterRulespecWithItem, + rulespec_registry, + RulespecGroupCheckParametersNetworking, +) + + +def _parameter_valuespec_cisco_asyncos_queue(): + return Dictionary(elements=[ + ('levels', + Tuple( + title=_('Levels for nuber of messages in work queue'), + elements=[ + Integer(title=_('Warning'), default_value=50, unit=_('# of messages')), + Integer(title=_('Critical'), default_value=100, unit=_('# of messages')), + ])), + ]) + + +rulespec_registry.register( + CheckParameterRulespecWithItem( + check_group_name='cisco_asyncos_queue', + group=RulespecGroupCheckParametersNetworking, + item_spec=lambda: TextAscii(title=_('Cisco AsyncOS queue'), ), + match_type='dict', + parameter_valuespec=_parameter_valuespec_cisco_asyncos_queue, + title=lambda: _('Cisco AsyncOS queue'), + )) diff --git a/web/plugins/wato/cisco_asyncos_update.py b/web/plugins/wato/cisco_asyncos_update.py index 6701443..930d2a9 100644 --- a/web/plugins/wato/cisco_asyncos_update.py +++ b/web/plugins/wato/cisco_asyncos_update.py @@ -1,31 +1,49 @@ -#!/usr/bin/python -# -*- encoding: utf-8; py-indent-offset: 4 -*- +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- # # -register_check_parameters( - subgroup_applications, - 'cisco_asyncos_update', - _('Cisco AsyncOS update'), - Dictionary( - # help=_(''), - elements=[ - ('features_ignore', - ListOfStrings( - title=_('update features to ignore'), - orientation='vertical', - help=_('there will be no warning/critical if this features are not updated' - 'Examples: geo_countries, timezones, etc.'), - ) - ), - ('failedLevel', - Tuple( - title=_('Levels for failed attempts'), - elements=[ - Integer(title=_('Warning'), default_value=5, unit=_('# of failed attempts')), - Integer(title=_('Critical'), default_value=10, unit=_('# of failed attempts')), - ])), - ], - ), - None, - match_type='dict', +from cmk.gui.i18n import _ +from cmk.gui.valuespec import ( + Dictionary, + Integer, + TextAscii, + ListOfStrings, + Tuple, ) + +from cmk.gui.plugins.wato import ( + CheckParameterRulespecWithItem, + rulespec_registry, + RulespecGroupCheckParametersNetworking, +) + + +def _parameter_valuespec_cisco_asyncos_license(): + return Dictionary(elements=[ + ('features_ignore', + ListOfStrings( + title=_('Update features to ignore'), + orientation='vertical', + help=_('there will be no warning/critical if this features are not updated' + 'Examples: geo_countries, timezones, etc.'), + ) + ), + ('failedLevel', + Tuple( + title=_('Levels for failed attempts'), + elements=[ + Integer(title=_('Warning'), default_value=5, unit=_('# of failed attempts')), + Integer(title=_('Critical'), default_value=10, unit=_('# of failed attempts')), + ])), + ]) + + +rulespec_registry.register( + CheckParameterRulespecWithItem( + check_group_name='cisco_asyncos_update', + group=RulespecGroupCheckParametersNetworking, + item_spec=lambda: TextAscii(title=_('Cisco AsyncOS update'), ), + match_type='dict', + parameter_valuespec=_parameter_valuespec_cisco_asyncos_update, + title=lambda: _('Cisco AsyncOS update'), + )) -- GitLab