diff --git a/agent_based/checkpoint_vsx_system.py b/agent_based/checkpoint_vsx_system.py index d9069908a0f13ef9cf511e07c885bb988153c7b3..8dfb77ab58adc3e72ae5a0b8990ece6f391b5735 100644 --- a/agent_based/checkpoint_vsx_system.py +++ b/agent_based/checkpoint_vsx_system.py @@ -23,6 +23,11 @@ # moved Main IP to details, if it is not an IPv4 address # 2022-10-23: fixed warning on upgrade "non-empty params vanished" for policyname and ha_state # 2023-05-29: moved gui files to ~/local/lib/check_mk/gui/plugins/... +# 2023-06-17: added support for predicted levels for connection active +# changed bytes/packets metrics to check_levels/check_levels_predictive +# 2023-06-18: cleanup variable names to better meet python standards +# + # # snmpwalk sample # @@ -92,7 +97,7 @@ import ipaddress import time from dataclasses import dataclass -from typing import List, Dict, Optional, Tuple +from typing import List, Dict, Optional, Any from cmk.base.plugins.agent_based.agent_based_api.v1 import ( register, @@ -109,6 +114,8 @@ from cmk.base.plugins.agent_based.agent_based_api.v1 import ( get_rate, GetRateError, check_levels, + check_levels_predictive, + render, ) from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( DiscoveryResult, @@ -117,55 +124,114 @@ from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import ( ) +@dataclass +class VsxMetric: + name: str + value: float + label: str + levels: str + render_func: Any + + @dataclass class CheckpointVsx: - vsxStatusVSId: str - vsxStatusVsType: str - vsxStatusMainIP: str - vsxStatusPolicyName: str - vsxStatusVsPolicyType: str - vsxStatusSicTrustState: str - vsxStatusHAState: str - vsxStatusVSWeight: str - vsxCountersConnNum: int - vsxCountersConnPeakNum: int - vsxCountersConnTableLimit: int - metrics_rate: List[Tuple[str, int]] + vs_id: str + vs_type: str + main_ip: str + policy_name: str + policy_type: str + sic_trust_state: str + ha_state: str + vs_weight: str + connections_active: int + connections_peak: int + connections_limit: int + metrics_rate: List[VsxMetric] + + +def _render_per_second(value: float) -> str: + return f'{value:.2}/s' def parse_checkpoint_vsx_system(string_table: StringTable) -> Optional[Dict[str, CheckpointVsx]]: vsx_systems = {} for entry in string_table: try: - vsxStatusVSId, vsxStatusVsName, vsxStatusVsType, vsxStatusMainIP, vsxStatusPolicyName, \ - vsxStatusVsPolicyType, vsxStatusSicTrustState, vsxStatusHAState, vsxStatusVSWeight, vsxCountersConnNum, \ - vsxCountersConnPeakNum, vsxCountersConnTableLimit, vsxCountersPackets, vsxCountersDroppedTotal, \ - vsxCountersAcceptedTotal, vsxCountersRejectedTotal, vsxCountersBytesAcceptedTotal, \ - vsxCountersBytesDroppedTotal, vsxCountersBytesRejectedTotal, vsxCountersLoggedTotal = entry + vs_id, vs_name, vs_type, main_ip, policy_name, policy_type, sic_trust_state, ha_state, vs_weight, \ + connections_active, connections_peak, connections_limit, packets_processed, packets_dropped, \ + packets_accepted, packets_rejected, bytes_accepted, bytes_dropped, bytes_rejected, loggs_send = entry except ValueError: return - vsx_systems[vsxStatusVsName] = CheckpointVsx( - vsxStatusVSId=vsxStatusVSId, - vsxStatusVsType=vsxStatusVsType, - vsxStatusMainIP=vsxStatusMainIP, - vsxStatusPolicyName=vsxStatusPolicyName, - vsxStatusVsPolicyType=vsxStatusVsPolicyType, - vsxStatusSicTrustState=vsxStatusSicTrustState, - vsxStatusHAState=vsxStatusHAState, - vsxStatusVSWeight=vsxStatusVSWeight, - vsxCountersConnNum=int(vsxCountersConnNum), - vsxCountersConnPeakNum=int(vsxCountersConnPeakNum), - vsxCountersConnTableLimit=int(vsxCountersConnTableLimit), + vsx_systems[vs_name] = CheckpointVsx( + vs_id=vs_id, + vs_type=vs_type, + main_ip=main_ip, + policy_name=policy_name, + policy_type=policy_type, + sic_trust_state=sic_trust_state, + ha_state=ha_state, + vs_weight=vs_weight, + connections_active=int(connections_active), + connections_peak=int(connections_peak), + connections_limit=int(connections_limit), metrics_rate=[ - ('packets_processed', int(vsxCountersPackets)), - ('packets_dropped', int(vsxCountersDroppedTotal)), - ('packets_accepted', int(vsxCountersAcceptedTotal)), - ('packets_rejected', int(vsxCountersRejectedTotal)), - ('bytes_accepted', int(vsxCountersBytesAcceptedTotal)), - ('bytes_dropped', int(vsxCountersBytesDroppedTotal)), - ('bytes_rejected', int(vsxCountersBytesRejectedTotal)), - ('loggs_send', int(vsxCountersLoggedTotal)), + VsxMetric( + name='bytes_accepted', + value=float(bytes_accepted), + label='Bytes accepted', + levels='levels_bytes_accepted', + render_func=render.iobandwidth, + ), + VsxMetric( + name='bytes_dropped', + value=float(bytes_dropped), + label='Bytes dropped', + levels='levels_bytes_dropped', + render_func=render.iobandwidth, + ), + VsxMetric( + name='bytes_rejected', + value=float(bytes_rejected), + label='Bytes rejected', + levels='levels_bytes_rejected', + render_func=render.iobandwidth, + ), + VsxMetric( + name='packets_accepted', + value=float(packets_accepted), + label='Packets accepted', + levels='levels_packets_accepted', + render_func=_render_per_second, + ), + VsxMetric( + name='packets_dropped', + value=float(packets_dropped), + label='Packets dropped', + levels='levels_packets_dropped', + render_func=_render_per_second, + ), + VsxMetric( + name='packets_rejected', + value=float(packets_rejected), + label='Packets rejected', + levels='levels_packets_rejected', + render_func=_render_per_second, + ), + VsxMetric( + name='packets_processed', + value=float(packets_processed), + label='Packets processed', + levels='levels_packets_processed', + render_func=_render_per_second, + ), + VsxMetric( + name='loggs_send', + value=float(loggs_send), + label='Logs send', + levels='levels_logs_send', + render_func=_render_per_second, + ), ], ) return vsx_systems @@ -173,90 +239,131 @@ def parse_checkpoint_vsx_system(string_table: StringTable) -> Optional[Dict[str, def discovery_checkpoint_vsx_system(params, section: Dict[str, CheckpointVsx]) -> DiscoveryResult: for key in section.keys(): - if section[key].vsxStatusVsType.lower() in params['vs_type']: + if section[key].vs_type.lower() in params['vs_type']: yield Service( item=key, - parameters={'policyname': section[key].vsxStatusPolicyName, 'ha_state': section[key].vsxStatusHAState} + parameters={'policyname': section[key].policy_name, 'ha_state': section[key].ha_state} ) def check_checkpoint_vsx_system(item, params, section: Dict[str, CheckpointVsx]) -> CheckResult: + # warn on old params + if params.get('levels_lower_absolute') or params.get('levels_upper_absolute'): + yield Result( + state=State.WARN, + summary='Reconfigure your "Check Point VSX System" WATO rule(s) please. ' + 'You are using deprecated settings (Maximum/Minimum number of firewall connections)' + ) + try: vsx = section[item] except KeyError: yield Result(state=State.UNKNOWN, notice='Item not found in SNMP data') return - if not vsx.vsxStatusSicTrustState.lower() in ['trust established']: + if not vsx.sic_trust_state.lower() in ['trust established']: yield Result(state=State(params['state_sic_not_established']), notice='SIC not established') - if vsx.vsxStatusVsType.lower() in ['virtual system', 'vsx gateway']: + if vsx.vs_type.lower() in ['virtual system', 'vsx gateway']: yield Result(state=State.OK, notice=f'System name: {item}') try: - yield Result(state=State.OK, summary=f'Main IP: {ipaddress.ip_address(vsx.vsxStatusMainIP)}') + yield Result(state=State.OK, summary=f'Main IP: {ipaddress.ip_address(vsx.main_ip)}') except ValueError: - yield Result(state=State.OK, notice=f'Main IP: {vsx.vsxStatusMainIP}') + yield Result(state=State.OK, notice=f'Main IP: {vsx.main_ip}') - yield Result(state=State.OK, summary=f'VS ID: {vsx.vsxStatusVSId}', - details=f'Virtual system ID: {vsx.vsxStatusVSId}') - yield Result(state=State.OK, notice=f'System type: {vsx.vsxStatusVsType}') + yield Result(state=State.OK, summary=f'VS ID: {vsx.vs_id}', details=f'Virtual system ID: {vsx.vs_id}') + yield Result(state=State.OK, notice=f'System type: {vsx.vs_type}') - if not vsx.vsxStatusHAState.lower() in ['active', 'standby']: - yield Result(state=State(params['state_ha_not_act_stb']), summary=f'H/A Status: {vsx.vsxStatusHAState}') + if not vsx.ha_state.lower() in ['active', 'standby']: + yield Result(state=State(params['state_ha_not_act_stb']), summary=f'H/A Status: {vsx.ha_state}') else: - yield Result(state=State.OK, summary=f'H/A Status: {vsx.vsxStatusHAState}') + yield Result(state=State.OK, summary=f'H/A Status: {vsx.ha_state}') - if not vsx.vsxStatusVsPolicyType.lower() in ['active']: + if not vsx.policy_type.lower() in ['active']: yield Result(state=State(params['state_policy_not_installed']), notice='No policy installed') - if params['policyname'] != vsx.vsxStatusPolicyName: # policy changed + if params['policyname'] != vsx.policy_name: # policy changed yield Result( state=State(params['state_policy_changed']), - notice=f'Policy name changed: expected {params["policyname"]}, found {vsx.vsxStatusPolicyName}' + notice=f'Policy name changed: expected {params["policyname"]}, found {vsx.policy_name}' ) - if params['ha_state'] != vsx.vsxStatusHAState: # H/A state changed + if params['ha_state'] != vsx.ha_state: # H/A state changed yield Result( state=State(params['state_ha_changed']), - notice=f'State changed: expected/found {params["ha_state"]}/{vsx.vsxStatusHAState}' + notice=f'State changed: expected/found {params["ha_state"]}/{vsx.ha_state}' ) - yield Result(state=State.OK, notice=f'SIC status: {vsx.vsxStatusSicTrustState}') - yield Result(state=State.OK, notice=f'Weight: {vsx.vsxStatusVSWeight}') - yield Result(state=State.OK, notice=f'Policy name: {vsx.vsxStatusPolicyName}') - yield Result(state=State.OK, notice=f'Policy type: {vsx.vsxStatusVsPolicyType}') + yield Result(state=State.OK, notice=f'SIC status: {vsx.sic_trust_state}') + yield Result(state=State.OK, notice=f'Weight: {vsx.vs_weight}') + yield Result(state=State.OK, notice=f'Policy name: {vsx.policy_name}') + yield Result(state=State.OK, notice=f'Policy type: {vsx.policy_type}') - # metrics rate - now_time = time.time() - value_store = get_value_store() metrics_prefix = 'checkpoint_vsx_' - for key, value in vsx.metrics_rate: - try: - value = get_rate(value_store, f'{metrics_prefix}{key}', now_time, int(value), raise_overflow=True) - except GetRateError: - value = 0 - yield Metric(name=f'checkpoint_vsx_{key}', value=value, boundaries=(0, None)) - # metrics count - yield from check_levels( - value=vsx.vsxCountersConnNum, + yield from check_levels_predictive( + value=vsx.connections_active, metric_name=f'{metrics_prefix}connections', - levels_upper=params.get('levels_upper_absolute'), - levels_lower=params.get('levels_lower_absolute'), + levels=params.get('levels_connections'), + label='Connections', + render_func=lambda v: f'{v:.0f}', + boundaries=(0, None), + ) if isinstance(params.get('levels_connections'), dict) else check_levels( + value=vsx.connections_active, + metric_name=f'{metrics_prefix}connections', + levels_upper=params.get('levels_connections'), + # levels_lower=params.get('levels_lower_absolute'), label='Connections', render_func=lambda v: f'{v:.0f}', boundaries=(0, None), ) - yield Metric(value=vsx.vsxCountersConnPeakNum, name=f'{metrics_prefix}connections_peak') - if vsx.vsxCountersConnTableLimit > 0: - yield Metric(value=vsx.vsxCountersConnTableLimit, name=f'{metrics_prefix}connections_limit') + # metrics rate + now_time = time.time() + value_store = get_value_store() + + for metric in vsx.metrics_rate: + try: + value = get_rate( + value_store, + f'{metrics_prefix}{metric.name}', + now_time, + metric.value, + raise_overflow=True, + ) + except GetRateError: + continue + # yield Metric(name=f'checkpoint_vsx_{key}', value=value, boundaries=(0, None)) + yield from check_levels_predictive( + value=value, + metric_name=f'checkpoint_vsx_{metric.name}', + levels=params.get(metric.levels), + label=metric.label, + render_func=metric.render_func, + boundaries=(0, None), + # needs patched lib/check_mk/base/api/agent_based/utils.py + # see PR https://github.com/Checkmk/checkmk/pull/598 + # notice_only=True, + ) if isinstance(params.get(metric.levels), dict) else check_levels( + value=value, + metric_name=f'checkpoint_vsx_{metric.name}', + levels_upper=params.get(metric.levels), + # levels_lower=params.get('levels_lower_absolute'), + label=metric.label, + render_func=metric.render_func, + boundaries=(0, None), + notice_only=True + ) + + yield Metric(value=vsx.connections_peak, name=f'{metrics_prefix}connections_peak') + if vsx.connections_limit > 0: + yield Metric(value=vsx.connections_limit, name=f'{metrics_prefix}connections_limit') else: yield Result(state=State.OK, notice=f'System name: {item}') - yield Result(state=State.OK, summary=f'Virtual system ID: {vsx.vsxStatusVSId}') - yield Result(state=State.OK, summary=f'System Type: {vsx.vsxStatusVsType}') - yield Result(state=State.OK, summary=f'SIC status: {vsx.vsxStatusSicTrustState}') + yield Result(state=State.OK, summary=f'Virtual system ID: {vsx.vs_id}') + yield Result(state=State.OK, summary=f'System Type: {vsx.vs_type}') + yield Result(state=State.OK, summary=f'SIC status: {vsx.sic_trust_state}') register.snmp_section( @@ -317,6 +424,7 @@ register.check_plugin( 'state_policy_not_installed': 2, 'state_policy_changed': 1, 'state_ha_changed': 1, + # 'levels_upper_absolute': (None, None), # 'levels_lower_absolute': (None, None), # 'policyname': '', diff --git a/checkpoint_vsx_system-0.5.0-20230619.mkp b/checkpoint_vsx_system-0.5.0-20230619.mkp new file mode 100644 index 0000000000000000000000000000000000000000..61e7c3a9f908950b4e7fc319972fcf51e61d9dcb Binary files /dev/null and b/checkpoint_vsx_system-0.5.0-20230619.mkp differ diff --git a/checkpoint_vsx_system.mkp b/checkpoint_vsx_system.mkp index 88eba84ef0a8f77eefa78bfdca353b8e0963ffa1..61e7c3a9f908950b4e7fc319972fcf51e61d9dcb 100644 Binary files a/checkpoint_vsx_system.mkp and b/checkpoint_vsx_system.mkp differ diff --git a/gui/wato/check_parameters/checkpoint_vsx_system.py b/gui/wato/check_parameters/checkpoint_vsx_system.py new file mode 100644 index 0000000000000000000000000000000000000000..f9ad001ff1d8ac0335161c5b16d51afc8d5a8424 --- /dev/null +++ b/gui/wato/check_parameters/checkpoint_vsx_system.py @@ -0,0 +1,139 @@ +#!/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 : 2021-09-07 +# + +# 2023-06-17: changed upper/lower levels for active connections to levels (predictive) +# added wato levels option for bytes/packets perf counters +# 2023-06-18: moved wato file to check_parameters sub directory + +from cmk.gui.i18n import _ +from cmk.gui.valuespec import ( + Dictionary, + TextAscii, + Tuple, + Integer, + MonitoringState, + ListChoice, + TextUnicode, +) + +from cmk.gui.plugins.wato.utils import ( + CheckParameterRulespecWithItem, + rulespec_registry, + RulespecGroupCheckParametersNetworking, + RulespecGroupCheckParametersDiscovery, + HostRulespec, + Levels, +) + + +def _parameter_valuespec_checkpoint_vsx_system(): + return Dictionary( + elements=[ + ('state_ha_not_act_stb', + MonitoringState( + title=_('State if H/A state is not active/standby'), + help=_('Monitoring state if H/A state is not active or standby. Defaulr is "CRIT"'), + default_value=2, + )), + ('state_ha_changed', + MonitoringState( + title=_('State if H/A state has changed'), + help=_('Monitoring state if H/A state has changed. Default is "WARN".'), + default_value=1, + )), + ('state_policy_not_installed', + MonitoringState( + title=_('State if no policy is installed'), + help=_('Monitoring state if no policy is installed. Default is "CRIT"'), + default_value=2, + )), + ('state_policy_changed', + MonitoringState( + title=_('State if policy name has changed'), + help=_('Monitoring status on policy name change. Default is "WARN".'), + default_value=1, + )), + ('state_sic_not_established', + MonitoringState( + title=_('State if SIC is not established'), + help=_('Monitoring state if SIC (Secure Internal Communication) is not established. Default is "CRIT"'), + default_value=2, + )), + ('levels_bytes_accepted', Levels(title=_('Levels for Bytes Accepted'), unit=_('Bytes/s'), )), + ('levels_bytes_dropped', Levels(title=_('Levels for Bytes Dropped'), unit=_('Bytes/s'), )), + ('levels_bytes_rejected', Levels(title=_('Levels for Bytes Rejected'), unit=_('Bytes/s'), )), + ('levels_connections', Levels(title=_('Levels for Connections'), unit=_('Connections'), )), + ('levels_logs_send', Levels(title=_('Levels for Logs Send'), unit=_('Logs/s'), )), + ('levels_packets_accepted', Levels(title=_('Levels for Packets Accepted'), unit=_('Packets/s'), )), + ('levels_packets_dropped', Levels(title=_('Levels for Packets Dropped'), unit=_('Packets/s'), )), + ('levels_packets_rejected', Levels(title=_('Levels for Packets Rejected'), unit=_('Packets/s'), )), + ('levels_packets_processed', Levels(title=_('Levels for Packets Processed'), unit=_('Packets/s'), )), + # added by plugin discovery function -> hidden key + ('policyname', TextUnicode()), + # added by plugin discovery function -> hidden key + ('ha_state', TextUnicode()), + ], + hidden_keys=['policyname', 'ha_state'], + ignored_keys=['levels_upper_absolute', 'levels_lower_absolute'], + # shows help before an item is activated, nur bei render "normal" + # columns=2, + # space saver -> Title to the Right -> item starts on same line. Adds collapsed properties + # form_part like form, only more space between label and checkbox + # render='form', + # item on same hight as label, is multiline item label moves to the middle of item -> saves space + # render form looks better + # form_narrow=True, + # same as form_narrow=True (?) + # form_isopen=False, + ) + + +rulespec_registry.register( + CheckParameterRulespecWithItem( + check_group_name='checkpoint_vsx_system', + group=RulespecGroupCheckParametersNetworking, + match_type='dict', + parameter_valuespec=_parameter_valuespec_checkpoint_vsx_system, + title=lambda: _('Check Point VSX system'), + item_spec=lambda: TextAscii(title=_('VSX System name'), ), + )) + + +def _valuespec_discovery_checkpoint_vsx_system(): + _vs_types = [ + ('virtual system', 'Virtual System'), + ('vsx gateway', 'VSX Gateway'), + ('virtual switch', 'Virtual Switch'), + ('virtual router', 'Virtual Router'), + ] + return Dictionary( + title=_('Check Point VSX system'), + elements=[ + ('vs_type', + ListChoice( + title=_('VS types to discover'), + help=_('Virtual system types to discover. Note: if you select "VSX Gateway", ' + 'this will also discover ClusterXL systems.'), + choices=_vs_types, + default_value=[ + 'virtual system', + ], + )), + ], + ) + + +rulespec_registry.register( + HostRulespec( + group=RulespecGroupCheckParametersDiscovery, + match_type='dict', + name='discovery_checkpoint_vsx_system', + valuespec=_valuespec_discovery_checkpoint_vsx_system, + )) diff --git a/packages/checkpoint_vsx_system b/packages/checkpoint_vsx_system index ee4de64a5fa57ed921fe5d0ed11345996671e18d..65f7d43a73e15016576b3113c3084c3cfa66d751 100644 --- a/packages/checkpoint_vsx_system +++ b/packages/checkpoint_vsx_system @@ -15,10 +15,10 @@ 'files': {'agent_based': ['checkpoint_vsx_system.py'], 'checkman': ['checkpoint_vsx_system'], 'gui': ['metrics/checkpoint_vsx_system.py', - 'wato/checkpoint_vsx_system.py']}, + 'wato/check_parameters/checkpoint_vsx_system.py']}, 'name': 'checkpoint_vsx_system', 'title': 'Check Point VSX system status and counter', - 'version': '0.4.0-20230529', + 'version': '0.5.0-20230619', 'version.min_required': '2.1.0b1', - 'version.packaged': '2.1.0p21', - 'version.usable_until': None} \ No newline at end of file + 'version.packaged': '2.2.0p2', + 'version.usable_until': None}