From 5a21b8bc5a8ec6defa1662e39dcfffda4d4ee00a Mon Sep 17 00:00:00 2001 From: OMD site cmk16x <thl-cmk@outlook.com> Date: Mon, 6 Mar 2023 15:05:55 +0100 Subject: [PATCH] update project --- agent_based/cisco_asyncos_bandwidth.py | 27 +++++++------ agent_based/cisco_asyncos_cache.py | 27 +++++++------ agent_based/cisco_asyncos_conn.py | 23 ++++++----- agent_based/cisco_asyncos_dns.py | 21 +++++----- agent_based/cisco_asyncos_messageage.py | 19 ++++----- agent_based/cisco_asyncos_queue.py | 23 ++++++----- agent_based/cisco_asyncos_resources.py | 19 ++++----- agent_based/cisco_asyncos_temp.py | 12 +++--- cisco_asyncos.mkp | Bin 11454 -> 10670 bytes gui/wato/cisco_asyncos_feature_keys.py | 50 +++++++++++++++++++++++ gui/wato/cisco_asyncos_license.py | 51 ++++++++++++++++++++++++ gui/wato/cisco_asyncos_queue.py | 41 +++++++++++++++++++ gui/wato/cisco_asyncos_updates.py | 49 +++++++++++++++++++++++ packages/cisco_asyncos | 15 ++++--- 14 files changed, 288 insertions(+), 89 deletions(-) create mode 100644 gui/wato/cisco_asyncos_feature_keys.py create mode 100644 gui/wato/cisco_asyncos_license.py create mode 100644 gui/wato/cisco_asyncos_queue.py create mode 100644 gui/wato/cisco_asyncos_updates.py diff --git a/agent_based/cisco_asyncos_bandwidth.py b/agent_based/cisco_asyncos_bandwidth.py index 0e4eccd..4d73994 100644 --- a/agent_based/cisco_asyncos_bandwidth.py +++ b/agent_based/cisco_asyncos_bandwidth.py @@ -9,8 +9,10 @@ # # only use full for Cisco WSA appliances # +# 2023-03-06: fixed: IndexError in parse function +# -from typing import Mapping, List, NamedTuple +from typing import Mapping, List, NamedTuple, Optional from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( DiscoveryResult, @@ -36,13 +38,16 @@ class CiscoAsyncosBandwidth(NamedTuple): bandwidth_day: int -# [[['0', '0', '247']]] -def parse_cisco_asyncos_bandwidth(string_table: List[StringTable]) -> CiscoAsyncosBandwidth: - return CiscoAsyncosBandwidth( - bandwidth_now=int(string_table[0][0][0]), - bandwidth_hour=int(string_table[0][0][1]), - bandwidth_day = int(string_table[0][0][2]), - ) +# [['0', '0', '247']] +def parse_cisco_asyncos_bandwidth(string_table: StringTable) -> Optional[CiscoAsyncosBandwidth]: + try: + return CiscoAsyncosBandwidth( + bandwidth_now=int(string_table[0][0]), + bandwidth_hour=int(string_table[0][1]), + bandwidth_day = int(string_table[0][2]), + ) + except IndexError: + return def discovery_cisco_asyncos_bandwidth(section: CiscoAsyncosBandwidth) -> DiscoveryResult: @@ -82,16 +87,14 @@ def check_cisco_asyncos_bandwidth(params, section: CiscoAsyncosBandwidth) -> Che register.snmp_section( name='cisco_asyncos_bandwidth', parse_function=parse_cisco_asyncos_bandwidth, - fetch=[ - SNMPTree( + fetch= SNMPTree( base='.1.3.6.1.4.1.15497.1.2.3.7.4', # ASYNCOSWEBSECURITYAPPLIANCE-MIB::proxyRecentBandWTotPerf oids=[ '1', # cacheBwidthTotalNow '3', # cacheBwidthTotal1hrMean '5', # cacheBwidthTotal1dayMean ] - ), - ], + ), detect=contains('.1.3.6.1.2.1.1.1.0', 'AsyncOS'), ) diff --git a/agent_based/cisco_asyncos_cache.py b/agent_based/cisco_asyncos_cache.py index dda48c6..bf53571 100644 --- a/agent_based/cisco_asyncos_cache.py +++ b/agent_based/cisco_asyncos_cache.py @@ -10,7 +10,7 @@ # only use full for Cisco WSA appliances # -from typing import Mapping, List, NamedTuple +from typing import Mapping, List, NamedTuple, Optional from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( DiscoveryResult, @@ -38,15 +38,18 @@ class CiscoAsyncosCache(NamedTuple): cache_total_resptime: int -# [[['0', '0', '0', '0', '0']]] -def parse_cisco_asyncos_cache(string_table: List[StringTable]) -> CiscoAsyncosCache: - return CiscoAsyncosCache( - cache_hits_now=int(string_table[0][0][0]), - cache_misses_now=int(string_table[0][0][1]), - cache_hit_resptime_now=int(string_table[0][0][2]), - cache_miss_resptime_now=int(string_table[0][0][3]), - cache_total_resptime=int(string_table[0][0][4]), - ) +# [['0', '0', '0', '0', '0']] +def parse_cisco_asyncos_cache(string_table: StringTable) -> Optional[CiscoAsyncosCache]: + try: + return CiscoAsyncosCache( + cache_hits_now=int(string_table[0][0]), + cache_misses_now=int(string_table[0][1]), + cache_hit_resptime_now=int(string_table[0][2]), + cache_miss_resptime_now=int(string_table[0][3]), + cache_total_resptime=int(string_table[0][4]), + ) + except IndexError: + return def discovery_cisco_asyncos_cache(section: CiscoAsyncosCache) -> DiscoveryResult: @@ -68,8 +71,7 @@ def check_cisco_asyncos_cache(params, section: CiscoAsyncosCache) -> CheckResult register.snmp_section( name='cisco_asyncos_cache', parse_function=parse_cisco_asyncos_cache, - fetch=[ - SNMPTree( + fetch= SNMPTree( base='.1.3.6.1.4.1.15497.1.2.3.7', # ASYNCOSWEBSECURITYAPPLIANCE-MIB::proxyRecentPerf oids=[ '5.1', # cacheHitsNow @@ -79,7 +81,6 @@ register.snmp_section( '9.1', # cacheTotalRespTimeNow ] ), - ], detect=contains('.1.3.6.1.2.1.1.1.0', 'AsyncOS'), ) diff --git a/agent_based/cisco_asyncos_conn.py b/agent_based/cisco_asyncos_conn.py index c5da832..f5436cd 100644 --- a/agent_based/cisco_asyncos_conn.py +++ b/agent_based/cisco_asyncos_conn.py @@ -9,7 +9,7 @@ # # only use full for Cisco WSA appliances # -from typing import Mapping, List, NamedTuple +from typing import Mapping, List, NamedTuple, Optional from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( DiscoveryResult, @@ -35,13 +35,16 @@ class CiscoAsyncosConn(NamedTuple): cacheClientMaxConns: int -# [[['0', '5', '66277']]] -def parse_cisco_asyncos_conn(string_table: List[StringTable]) -> CiscoAsyncosConn: - return CiscoAsyncosConn( - cacheClientIdleConns=int(string_table[0][0][0]), - cacheClientTotalConns=int(string_table[0][0][1]), - cacheClientMaxConns=int(string_table[0][0][2]), - ) +# [['0', '5', '66277']] +def parse_cisco_asyncos_conn(string_table: StringTable) -> Optional[CiscoAsyncosConn]: + try: + return CiscoAsyncosConn( + cacheClientIdleConns=int(string_table[0][0]), + cacheClientTotalConns=int(string_table[0][1]), + cacheClientMaxConns=int(string_table[0][2]), + ) + except IndexError: + return def discovery_cisco_asyncos_conn(section: CiscoAsyncosConn) -> DiscoveryResult: @@ -61,8 +64,7 @@ def check_cisco_asyncos_conn(params, section: CiscoAsyncosConn) -> CheckResult: register.snmp_section( name='cisco_asyncos_conn', parse_function=parse_cisco_asyncos_conn, - fetch=[ - SNMPTree( + fetch= SNMPTree( base='.1.3.6.1.4.1.15497.1.2.3.2', # ASYNCOSWEBSECURITYAPPLIANCE-MIB::proxyClientSidePerf oids=[ '7', # cacheClientIdleConns @@ -70,7 +72,6 @@ register.snmp_section( '9', # cacheClientMaxConns ] ), - ], detect=contains('.1.3.6.1.2.1.1.1.0', 'AsyncOS'), ) diff --git a/agent_based/cisco_asyncos_dns.py b/agent_based/cisco_asyncos_dns.py index 664d265..534f79a 100644 --- a/agent_based/cisco_asyncos_dns.py +++ b/agent_based/cisco_asyncos_dns.py @@ -19,7 +19,7 @@ # ASYNCOS-MAIL-MIB::pendingDNSRequests.0 = Gauge32: 0 # # -from typing import Mapping, List, NamedTuple +from typing import Mapping, List, NamedTuple, Optional from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( DiscoveryResult, @@ -44,12 +44,15 @@ class CiscoAsyncosDns(NamedTuple): pendingDNSRequests: int -# [[['0', '0']]] -def parse_cisco_asyncos_dns(string_table: List[StringTable]) -> CiscoAsyncosDns: - return CiscoAsyncosDns( - outstandingDNSRequests=int(string_table[0][0][0]), - pendingDNSRequests=int(string_table[0][0][1]), - ) +# [['0', '0']] +def parse_cisco_asyncos_dns(string_table: StringTable) -> Optional[CiscoAsyncosDns]: + try: + return CiscoAsyncosDns( + outstandingDNSRequests=int(string_table[0][0]), + pendingDNSRequests=int(string_table[0][1]), + ) + except IndexError: + return def discovery_cisco_asyncos_dns(section: CiscoAsyncosDns) -> DiscoveryResult: @@ -68,15 +71,13 @@ def check_cisco_asyncos_dns(params, section: CiscoAsyncosDns) -> CheckResult: register.snmp_section( name='cisco_asyncos_dns', parse_function=parse_cisco_asyncos_dns, - fetch=[ - SNMPTree( + fetch= SNMPTree( base='.1.3.6.1.4.1.15497.1.1.1', # ASYNCOS-MAIL-MIB oids=[ '15', # outstandingDNSRequests '16', # pendingDNSRequests ] ), - ], detect=contains('.1.3.6.1.2.1.1.1.0', 'AsyncOS'), ) diff --git a/agent_based/cisco_asyncos_messageage.py b/agent_based/cisco_asyncos_messageage.py index d078942..91383d7 100644 --- a/agent_based/cisco_asyncos_messageage.py +++ b/agent_based/cisco_asyncos_messageage.py @@ -17,7 +17,7 @@ # ASYNCOS-MAIL-MIB::oldestMessageAge.0 = Gauge32: 259706 # -from typing import Mapping, List, NamedTuple +from typing import Mapping, List, NamedTuple, Optional from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( DiscoveryResult, @@ -41,11 +41,14 @@ from cmk.base.plugins.agent_based.agent_based_api.v1 import ( class CiscoAsyncosMessageage(NamedTuple): messageage: int -# [[['259297']]] -def parse_cisco_asyncos_messageage(string_table: List[StringTable]) -> CiscoAsyncosMessageage: - return CiscoAsyncosMessageage( - messageage=int(string_table[0][0][0]), - ) +# [['259297']] +def parse_cisco_asyncos_messageage(string_table: StringTable) -> Optional[CiscoAsyncosMessageage]: + try: + return CiscoAsyncosMessageage( + messageage=int(string_table[0][0]), + ) + except IndexError: + return def discovery_cisco_asyncos_messageage(section: CiscoAsyncosMessageage) -> DiscoveryResult: @@ -65,14 +68,12 @@ def check_cisco_asyncos_messageage(params, section: CiscoAsyncosMessageage) -> C register.snmp_section( name='cisco_asyncos_messageage', parse_function=parse_cisco_asyncos_messageage, - fetch=[ - SNMPTree( + fetch= SNMPTree( base='.1.3.6.1.4.1.15497.1.1.1', # ASYNCOS-MAIL-MIB oids=[ '14', # oldestMessageAge ] ), - ], detect=contains('.1.3.6.1.2.1.1.1.0', 'AsyncOS'), ) diff --git a/agent_based/cisco_asyncos_queue.py b/agent_based/cisco_asyncos_queue.py index 32a67a2..b4a7988 100644 --- a/agent_based/cisco_asyncos_queue.py +++ b/agent_based/cisco_asyncos_queue.py @@ -12,7 +12,7 @@ # 2021-03-24: rewrite for CMK 2.0 # -from typing import Mapping, List, NamedTuple +from typing import Mapping, List, NamedTuple, Optional from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( DiscoveryResult, @@ -56,13 +56,16 @@ def get_cmk_state(st: str) -> State: return states.get(st, State.CRIT) -# [[['1', '1']]] -def parse_cisco_asyncos_messageage(string_table: List[StringTable]) -> CiscoAsyncosQueue: - return CiscoAsyncosQueue( - state=get_cmk_state(string_table[0][0][0]), - status_readable=get_status_readable(string_table[0][0][0]), - workQueueMessages=int(string_table[0][0][1]) - ) +# [['1', '1']] +def parse_cisco_asyncos_messageage(string_table: StringTable) -> Optional[CiscoAsyncosQueue]: + try: + return CiscoAsyncosQueue( + state=get_cmk_state(string_table[0][0]), + status_readable=get_status_readable(string_table[0][0]), + workQueueMessages=int(string_table[0][1]) + ) + except IndexError: + return def discovery_cisco_asyncos_queue(section: CiscoAsyncosQueue) -> DiscoveryResult: @@ -82,15 +85,13 @@ def check_cisco_asyncos_queue(params, section: CiscoAsyncosQueue) -> CheckResult register.snmp_section( name='cisco_asyncos_queue', parse_function=parse_cisco_asyncos_messageage, - fetch=[ - SNMPTree( + fetch= SNMPTree( base='.1.3.6.1.4.1.15497.1.1.1', # ASYNCOS-MAIL-MIB oids=[ '5', # queueAvailabilityStatus '11' # workQueueMessages ] ), - ], detect=contains('.1.3.6.1.2.1.1.1.0', 'AsyncOS'), ) diff --git a/agent_based/cisco_asyncos_resources.py b/agent_based/cisco_asyncos_resources.py index 0f4cda0..c6041a2 100644 --- a/agent_based/cisco_asyncos_resources.py +++ b/agent_based/cisco_asyncos_resources.py @@ -17,7 +17,7 @@ # ASYNCOS-MAIL-MIB::resourceConservationReason.0 = INTEGER: noResourceConservation(1) # # -from typing import Mapping, List, NamedTuple +from typing import Mapping, List, NamedTuple, Optional from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( DiscoveryResult, @@ -62,11 +62,14 @@ class CiscoAsyncosResources(NamedTuple): status_readable: str -def parse_cisco_asyncos_bandwidth(string_table: List[StringTable]) -> CiscoAsyncosResources: - return CiscoAsyncosResources( - state=get_cmk_state(string_table[0][0][0]), - status_readable=get_status_readable(string_table[0][0][0]) - ) +def parse_cisco_asyncos_bandwidth(string_table: StringTable) -> Optional[CiscoAsyncosResources]: + try: + return CiscoAsyncosResources( + state=get_cmk_state(string_table[0][0]), + status_readable=get_status_readable(string_table[0][0]) + ) + except IndexError: + return def discovery_cisco_asyncos_resources(section: CiscoAsyncosResources) -> DiscoveryResult: @@ -80,14 +83,12 @@ def check_cisco_asyncos_resources(section: CiscoAsyncosResources) -> CheckResult register.snmp_section( name='cisco_asyncos_resources', parse_function=parse_cisco_asyncos_bandwidth, - fetch=[ - SNMPTree( + fetch= SNMPTree( base='.1.3.6.1.4.1.15497.1.1.1', # ASYNCOS-MAIL-MIB oids=[ '6', # resourceConservationReason ] ), - ], detect=contains('.1.3.6.1.2.1.1.1.0', 'AsyncOS'), ) diff --git a/agent_based/cisco_asyncos_temp.py b/agent_based/cisco_asyncos_temp.py index d2d0fe1..bb38d10 100644 --- a/agent_based/cisco_asyncos_temp.py +++ b/agent_based/cisco_asyncos_temp.py @@ -36,6 +36,7 @@ from cmk.base.plugins.agent_based.agent_based_api.v1 import ( check_levels, SNMPTree, contains, + get_value_store, ) from cmk.base.plugins.agent_based.utils.temperature import ( @@ -45,11 +46,11 @@ from cmk.base.plugins.agent_based.utils.temperature import ( # -# [[['22', 'FP_TEMP_SENSOR']]] +# [['22', 'FP_TEMP_SENSOR']] # -def parse_cisco_asyncos_temp(string_table: List[StringTable]) -> dict: +def parse_cisco_asyncos_temp(string_table: StringTable) -> dict: sensors = {} - for sensor in string_table[0]: + for sensor in string_table: try: value, item = sensor item = item.replace('_', ' ') @@ -70,6 +71,7 @@ def check_cisco_asyncos_temp(item, params: TempParamType, section) -> CheckResul section[item], params=params, unique_name='check_cisco_asyncos_temp.%s' % item, + value_store=get_value_store(), ) except KeyError: pass @@ -78,15 +80,13 @@ def check_cisco_asyncos_temp(item, params: TempParamType, section) -> CheckResul register.snmp_section( name='cisco_asyncos_temp', parse_function=parse_cisco_asyncos_temp, - fetch=[ - SNMPTree( + fetch= SNMPTree( base='.1.3.6.1.4.1.15497.1.1.1.9.1', # ASYNCOS-MAIL-MIB::temperatureEntry oids=[ '2', # degreesCelsius '3', # temperatureName ] ), - ], detect=contains('.1.3.6.1.2.1.1.1.0', 'AsyncOS'), ) diff --git a/cisco_asyncos.mkp b/cisco_asyncos.mkp index 3102a3f16c6c7ba54cb850112f5f2df6cb36ff9b..60bcf605212b7552bb0db41df2d304ff042462d5 100644 GIT binary patch literal 10670 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 VS_l5$Xexpr>bJR_L8U-L{XZKJ^2GoE literal 11454 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 WK>ELW7twM+Xwp|Q?hx&e5dQ<YyRxJJ diff --git a/gui/wato/cisco_asyncos_feature_keys.py b/gui/wato/cisco_asyncos_feature_keys.py new file mode 100644 index 0000000..8b38a99 --- /dev/null +++ b/gui/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.utils 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/gui/wato/cisco_asyncos_license.py b/gui/wato/cisco_asyncos_license.py new file mode 100644 index 0000000..fb7cbca --- /dev/null +++ b/gui/wato/cisco_asyncos_license.py @@ -0,0 +1,51 @@ +#!/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.utils import ( + CheckParameterRulespecWithItem, + rulespec_registry, + RulespecGroupCheckParametersNetworking, +) + + +def _parameter_valuespec_cisco_asyncos_license(): + return Dictionary(elements=[ + ('features_ignore', + ListOfStrings( + title=_('License features to ignore'), + orientation='vertical', + allow_empty=False, + # valuespec=Integer(minvalue=1, maxvalue=99), + 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 licence 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_license', + group=RulespecGroupCheckParametersNetworking, + item_spec=lambda: TextAscii(title=_('Cisco AsyncOS license'), ), + match_type='dict', + parameter_valuespec=_parameter_valuespec_cisco_asyncos_license, + title=lambda: _('Cisco AsyncOS license'), + )) diff --git a/gui/wato/cisco_asyncos_queue.py b/gui/wato/cisco_asyncos_queue.py new file mode 100644 index 0000000..66d0258 --- /dev/null +++ b/gui/wato/cisco_asyncos_queue.py @@ -0,0 +1,41 @@ +#!/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.utils 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/gui/wato/cisco_asyncos_updates.py b/gui/wato/cisco_asyncos_updates.py new file mode 100644 index 0000000..4f25b4d --- /dev/null +++ b/gui/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.utils 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'), + )) diff --git a/packages/cisco_asyncos b/packages/cisco_asyncos index ab2cde2..40f7910 100644 --- a/packages/cisco_asyncos +++ b/packages/cisco_asyncos @@ -39,14 +39,13 @@ 'cisco_asyncos_resources.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']}, + 'gui': ['wato/cisco_asyncos_feature_keys.py', + 'wato/cisco_asyncos_license.py', + 'wato/cisco_asyncos_queue.py', + 'wato/cisco_asyncos_updates.py']}, 'name': 'cisco_asyncos', - 'num_files': 19, 'title': 'Cisco AsyncOS (IronPort) checks', - 'version': '20210324_v0.2.0', - 'version.min_required': '2.0.0', - 'version.packaged': '2.0.0p1', + 'version': '20230306.v0.3.0', + 'version.min_required': '2.1.0', + 'version.packaged': '2.1.0p22', 'version.usable_until': None} \ No newline at end of file -- GitLab