From 85a7de5b97ce1901db98bdd644f69d54d446cb10 Mon Sep 17 00:00:00 2001 From: "th.l" <thl-cmk@outlook.com> Date: Sun, 18 Jun 2023 20:03:09 +0200 Subject: [PATCH] update project --- agent_based/checkpoint_vsx_system.py | 266 ++++++++++++------ checkpoint_vsx_system-0.5.0-20230619.mkp | Bin 0 -> 7391 bytes checkpoint_vsx_system.mkp | Bin 6360 -> 7391 bytes .../check_parameters/checkpoint_vsx_system.py | 139 +++++++++ packages/checkpoint_vsx_system | 8 +- 5 files changed, 330 insertions(+), 83 deletions(-) create mode 100644 checkpoint_vsx_system-0.5.0-20230619.mkp create mode 100644 gui/wato/check_parameters/checkpoint_vsx_system.py diff --git a/agent_based/checkpoint_vsx_system.py b/agent_based/checkpoint_vsx_system.py index d906990..8dfb77a 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 GIT binary patch literal 7391 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 literal 0 HcmV?d00001 diff --git a/checkpoint_vsx_system.mkp b/checkpoint_vsx_system.mkp index 88eba84ef0a8f77eefa78bfdca353b8e0963ffa1..61e7c3a9f908950b4e7fc319972fcf51e61d9dcb 100644 GIT binary patch literal 7391 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 literal 6360 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 b{@+jHe;5D%&)li?qF>TqwPRzPV_^IbHXni? 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 0000000..f9ad001 --- /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 ee4de64..65f7d43 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} -- GitLab