From cb062fb66c7a4a52307d78061577b622fde918da Mon Sep 17 00:00:00 2001 From: "Th.L" <thl-cmk@outlook.com> Date: Fri, 26 Mar 2021 20:15:43 +0100 Subject: [PATCH] update project --- agent_based/cisco_asyncos_cpu.py | 4 +- agent_based/cisco_asyncos_fan.py | 4 +- ...cense.py => cisco_asyncos_feature_keys.py} | 20 +-- agent_based/cisco_asyncos_power.py | 4 +- agent_based/cisco_asyncos_temp.py | 6 +- ...cos_update.py => cisco_asyncos_updates.py} | 149 ++++++++---------- cisco_asyncos.mkp | Bin 11593 -> 11454 bytes packages/cisco_asyncos | 12 +- .../wato/cisco_asyncos_feature_keys.py | 50 ++++++ web/plugins/wato/cisco_asyncos_updates.py | 49 ++++++ 10 files changed, 193 insertions(+), 105 deletions(-) rename agent_based/{cisco_asyncos_license.py => cisco_asyncos_feature_keys.py} (94%) rename agent_based/{cisco_asyncos_update.py => cisco_asyncos_updates.py} (68%) create mode 100644 web/plugins/wato/cisco_asyncos_feature_keys.py create mode 100644 web/plugins/wato/cisco_asyncos_updates.py diff --git a/agent_based/cisco_asyncos_cpu.py b/agent_based/cisco_asyncos_cpu.py index 5822be0..5123500 100644 --- a/agent_based/cisco_asyncos_cpu.py +++ b/agent_based/cisco_asyncos_cpu.py @@ -9,13 +9,13 @@ from typing import Mapping, Dict, List, Tuple, NamedTuple -from .agent_based_api.v1.type_defs import ( +from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( DiscoveryResult, CheckResult, StringTable, ) -from .agent_based_api.v1 import ( +from cmk.base.plugins.agent_based.agent_based_api.v1 import ( register, Service, check_levels, diff --git a/agent_based/cisco_asyncos_fan.py b/agent_based/cisco_asyncos_fan.py index 13363dc..13e6618 100644 --- a/agent_based/cisco_asyncos_fan.py +++ b/agent_based/cisco_asyncos_fan.py @@ -43,13 +43,13 @@ from typing import Dict, List -from .agent_based_api.v1.type_defs import ( +from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( DiscoveryResult, CheckResult, StringTable, ) -from .agent_based_api.v1 import ( +from cmk.base.plugins.agent_based.agent_based_api.v1 import ( register, Service, check_levels, diff --git a/agent_based/cisco_asyncos_license.py b/agent_based/cisco_asyncos_feature_keys.py similarity index 94% rename from agent_based/cisco_asyncos_license.py rename to agent_based/cisco_asyncos_feature_keys.py index 91f8e42..4d75a73 100644 --- a/agent_based/cisco_asyncos_license.py +++ b/agent_based/cisco_asyncos_feature_keys.py @@ -156,7 +156,7 @@ class CiscoAsyncosLicense(NamedTuple): # ['Outbreak Filters', '2', '32542740'], # ['Sophos Anti-Virus', '2', '32542740'] # ]] -def parse_cisco_asyncos_license(string_table: List[StringTable]) -> Mapping[str, CiscoAsyncosLicense]: +def parse_cisco_asyncos_feature_keys(string_table: List[StringTable]) -> Mapping[str, CiscoAsyncosLicense]: licenses = {} for license, isperpetual, secondsuntilexpire in string_table[0]: licenses.update({license: CiscoAsyncosLicense( @@ -182,12 +182,12 @@ def parse_cisco_asyncos_license(string_table: List[StringTable]) -> Mapping[str, # 'Sophos Anti-Virus': CiscoAsyncosLicense(perpetual=False, secondsuntilexpire=32542740, daysuntilexpire=376, expiredate='06 Apr 2022') # } -def discovery_cisco_asyncos_license(section: Mapping[str, CiscoAsyncosLicense]) -> DiscoveryResult: +def discovery_cisco_asyncos_feature_keys(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: +def check_cisco_asyncos_feature_keys(params, section: Mapping[str, CiscoAsyncosLicense]) -> CheckResult: features_ignore = params.get('features_ignore', []) warn, crit = params.get('expire') ignore_count = 0 @@ -215,8 +215,8 @@ def check_cisco_asyncos_license(params, section: Mapping[str, CiscoAsyncosLicens register.snmp_section( - name='cisco_asyncos_license', - parse_function=parse_cisco_asyncos_license, + name='cisco_asyncos_feature_keys', + parse_function=parse_cisco_asyncos_feature_keys, fetch=[ SNMPTree( base='.1.3.6.1.4.1.15497.1.1.1.12.1', # ASYNCOS-MAIL-MIB::keyExpirationEntry @@ -231,10 +231,10 @@ register.snmp_section( ) register.check_plugin( - name='cisco_asyncos_license', - service_name='License', - discovery_function=discovery_cisco_asyncos_license, - check_function=check_cisco_asyncos_license, + name='cisco_asyncos_feature_keys', + service_name='Feature keys', + discovery_function=discovery_cisco_asyncos_feature_keys, + check_function=check_cisco_asyncos_feature_keys, check_default_parameters={'expire': (30, 7)}, - check_ruleset_name='cisco_asyncos_license', + check_ruleset_name='cisco_asyncos_feature_keys', ) diff --git a/agent_based/cisco_asyncos_power.py b/agent_based/cisco_asyncos_power.py index d63ef49..2ea635e 100644 --- a/agent_based/cisco_asyncos_power.py +++ b/agent_based/cisco_asyncos_power.py @@ -34,13 +34,13 @@ from typing import Dict, List, NamedTuple -from .agent_based_api.v1.type_defs import ( +from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( DiscoveryResult, CheckResult, StringTable, ) -from .agent_based_api.v1 import ( +from cmk.base.plugins.agent_based.agent_based_api.v1 import ( register, Service, Result, diff --git a/agent_based/cisco_asyncos_temp.py b/agent_based/cisco_asyncos_temp.py index a8b4769..d2d0fe1 100644 --- a/agent_based/cisco_asyncos_temp.py +++ b/agent_based/cisco_asyncos_temp.py @@ -24,13 +24,13 @@ from typing import Mapping, Dict, List, Tuple, NamedTuple -from .agent_based_api.v1.type_defs import ( +from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( DiscoveryResult, CheckResult, StringTable, ) -from .agent_based_api.v1 import ( +from cmk.base.plugins.agent_based.agent_based_api.v1 import ( register, Service, check_levels, @@ -38,7 +38,7 @@ from .agent_based_api.v1 import ( contains, ) -from .utils.temperature import ( +from cmk.base.plugins.agent_based.utils.temperature import ( check_temperature, TempParamType, ) diff --git a/agent_based/cisco_asyncos_update.py b/agent_based/cisco_asyncos_updates.py similarity index 68% rename from agent_based/cisco_asyncos_update.py rename to agent_based/cisco_asyncos_updates.py index 3e18099..db567ce 100644 --- a/agent_based/cisco_asyncos_update.py +++ b/agent_based/cisco_asyncos_updates.py @@ -7,7 +7,7 @@ # URL : https://thl-cmk.hopto.org # Date : 2020-02-19 # -# 2020-05-14: added wato oprion to ignore items +# 2020-05-14: added wato option to ignore items # 2021-03-25: rewrite for CMK2.0 # # @@ -148,14 +148,17 @@ from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( from cmk.base.plugins.agent_based.agent_based_api.v1 import ( register, Service, - check_levels, Result, SNMPTree, contains, State, - render, + Metric, ) +from cmk.base.item_state import ( + get_item_state, + set_item_state, +) class CiscoAsyncosUpdate(NamedTuple): updates: int @@ -178,7 +181,7 @@ class CiscoAsyncosUpdate(NamedTuple): # ['support_request', '1', '0'], # ['timezones', '1', '0'] # ]] -def parse_cisco_asyncos_update(string_table: List[StringTable]) -> Mapping[str, CiscoAsyncosUpdate]: +def parse_cisco_asyncos_updates(string_table: List[StringTable]) -> Mapping[str, CiscoAsyncosUpdate]: features = {} for feature, updates, update_failures in string_table[0]: features.update({feature: CiscoAsyncosUpdate( @@ -204,90 +207,76 @@ def parse_cisco_asyncos_update(string_table: List[StringTable]) -> Mapping[str, # 'support_request': CiscoAsyncosUpdate(updates=1, updatefailures=0), # 'timezones': CiscoAsyncosUpdate(updates=1, updatefailures=0) # } -def discovery_cisco_asyncos_update(section:Mapping[str, CiscoAsyncosUpdate])-> DiscoveryResult: +def discovery_cisco_asyncos_updates(section:Mapping[str, CiscoAsyncosUpdate])-> DiscoveryResult: yield Service() -def check_cisco_asyncos_update(params, section:Mapping[str, CiscoAsyncosUpdate]) -> CheckResult: +def check_cisco_asyncos_updates(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 + failed = section[feature].updatefailures + passed = section[feature].updates + + # read counters + passedLast = get_item_state('cisco_asyncos_updates_%s_passedLast' % feature) + failedLast = get_item_state('cisco_asyncos_updates_%s_failedLast' % feature) + failedAttempts = get_item_state('cisco_asyncos_updates_%s_failedAttempts' % feature) + + # print('Feature %s, passed: %s/%s failed: %s/%s, Attempts: %s' % (feature, passed,passedLast, failed,failedLast, failedAttempts)) + + if (passedLast == None) or (failedLast == None) or (failedAttempts == None): # or (lastState == None): + # init counters + set_item_state('cisco_asyncos_updates_%s_passedLast' % feature, passed) + set_item_state('cisco_asyncos_updates_%s_failedLast' % feature, failed) + set_item_state('cisco_asyncos_updates_%s_failedAttempts' % feature, 0) else: - yield Result(state=State.OK, notice='Feature %s: %d/%d updates/update failures. Feature ignored!' % (feature, section[feature].updates, section[feature].updatefailures)) + set_item_state('cisco_asyncos_updates_%s_passedLast' % feature, passed) + set_item_state('cisco_asyncos_updates_%s_failedLast' % feature, failed) + passedLast = int(passedLast) + failedLast = int(failedLast) + failedAttempts = int(failedAttempts) - yield Result(state=State.OK, summary='%d/%d Features found/ignored' % (len(section.keys()), ignore_count)) + # reset counter if overrun + if failed < failedLast: + set_item_state('cisco_asyncos_updates_%s_failedLast' % feature, failed) + failedLast = failed + if passed < passedLast: + set_item_state('cisco_asyncos_updates_%s_passedLast' % feature, passed) + passedLast = passed + + if passed > passedLast: + # reset error counter after passed update attempt + set_item_state('cisco_asyncos_updates_%s_failedAttempts' % feature, 0) + else: + failedAttempts = failedAttempts + failed - failedLast + set_item_state('cisco_asyncos_updates_%s_failedAttempts' % feature, failedAttempts) + if feature in features_ignore: + yield Result(state=State.OK, notice='%s: %d/%d updates/update failures. Feature ignored!' % (feature, passed, failed)) + ignore_count += 1 + else: + if failedAttempts >= crit: + yield Result(state=State.CRIT, notice='%s: %d/%d passed/failed.' % (feature, passed, failed)) + lastState=-1 + elif failedAttempts >= warn: + yield Result(state=State.WARN, notice='%s: %d/%d passed/failed.' % (feature, passed, failed)) + lastState=-1 + else: + yield Result(state=State.OK, notice='%s: %d/%d passed/failed.' % (feature, passed, failed)) + lastState=1 - # 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 + yield Metric( + name=feature.replace(' ', '_'), + value=lastState, + boundaries=(2,-2) + ) + yield Result(state=State.OK, summary='%d/%d Features found/ignored' % (len(section.keys()), ignore_count)) register.snmp_section( - name='cisco_asyncos_update', - parse_function=parse_cisco_asyncos_update, + name='cisco_asyncos_updates', + parse_function=parse_cisco_asyncos_updates, fetch=[ SNMPTree( base='.1.3.6.1.4.1.15497.1.1.1.13.1', # ASYNCOS-MAIL-MIB::updateEntry @@ -302,11 +291,11 @@ register.snmp_section( ) register.check_plugin( - name='cisco_asyncos_update', - service_name='Update', - discovery_function=discovery_cisco_asyncos_update, - check_function=check_cisco_asyncos_update, + name='cisco_asyncos_updates', + service_name='Updates', + discovery_function=discovery_cisco_asyncos_updates, + check_function=check_cisco_asyncos_updates, check_default_parameters={'failedLevel': (5, 10)}, - check_ruleset_name='cisco_asyncos_update', + check_ruleset_name='cisco_asyncos_updates', ) diff --git a/cisco_asyncos.mkp b/cisco_asyncos.mkp index c654bdad2d4fea5d73745de47ea1d405cbb3442f..3102a3f16c6c7ba54cb850112f5f2df6cb36ff9b 100644 GIT binary patch literal 11454 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 WK>ELW7twM+Xwp|Q?hx&e5dQ<YyRxJJ literal 11593 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 MUtwgZc4(;o0c-py3;+NC diff --git a/packages/cisco_asyncos b/packages/cisco_asyncos index 0919172..ab2cde2 100644 --- a/packages/cisco_asyncos +++ b/packages/cisco_asyncos @@ -37,12 +37,12 @@ 'cisco_asyncos_messageage.py', 'cisco_asyncos_queue.py', 'cisco_asyncos_resources.py', - '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', - 'plugins/metrics/cisco_asyncos.py']}, + 'cisco_asyncos_feature_keys.py', + 'cisco_asyncos_updates.py'], + 'web': ['plugins/wato/cisco_asyncos_queue.py', + 'plugins/metrics/cisco_asyncos.py', + 'plugins/wato/cisco_asyncos_feature_keys.py', + 'plugins/wato/cisco_asyncos_updates.py']}, 'name': 'cisco_asyncos', 'num_files': 19, 'title': 'Cisco AsyncOS (IronPort) checks', diff --git a/web/plugins/wato/cisco_asyncos_feature_keys.py b/web/plugins/wato/cisco_asyncos_feature_keys.py new file mode 100644 index 0000000..47cc786 --- /dev/null +++ b/web/plugins/wato/cisco_asyncos_feature_keys.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# +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_feature_keys(): + return Dictionary(elements=[ + ('features_ignore', + ListOfStrings( + title=_('feature keys features to ignore'), + orientation='vertical', + allow_empty=False, + help=_('there will be no warning/critical if this features are expired' + 'Examples: McAfee, IronPort Email Encryption, Data Loss Prevention, etc.'), + ) + ), + ('expire', + Tuple( + title=_('Levels for feature key expiration in days'), + elements=[ + Integer(title=_('Warning'), default_value=30, unit=_('days before expiration')), + Integer(title=_('Critical'), default_value=7, unit=_('days before expiration')), + ])), + ]) + + +rulespec_registry.register( + CheckParameterRulespecWithItem( + check_group_name='cisco_asyncos_feature_keys', + group=RulespecGroupCheckParametersNetworking, + item_spec=lambda: TextAscii(title=_('Cisco AsyncOS feature keys'), ), + match_type='dict', + parameter_valuespec=_parameter_valuespec_cisco_asyncos_feature_keys, + title=lambda: _('Cisco AsyncOS feature keys'), + )) diff --git a/web/plugins/wato/cisco_asyncos_updates.py b/web/plugins/wato/cisco_asyncos_updates.py new file mode 100644 index 0000000..9344a58 --- /dev/null +++ b/web/plugins/wato/cisco_asyncos_updates.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# +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_updates(): + 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_updates', + group=RulespecGroupCheckParametersNetworking, + item_spec=lambda: TextAscii(title=_('Cisco AsyncOS updates'), ), + match_type='dict', + parameter_valuespec=_parameter_valuespec_cisco_asyncos_updates, + title=lambda: _('Cisco AsyncOS updates'), + )) -- GitLab