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