From 309e3fd4ccd7f05a36cfb65af59e83428cc178c0 Mon Sep 17 00:00:00 2001
From: "th.l" <thl-cmk@outlook.com>
Date: Sat, 22 Apr 2023 11:46:44 +0200
Subject: [PATCH] update project

---
 CHANGELOG                    |   4 +-
 gui/metrics/ospf_neighbor.py |  69 +++++++++++++
 gui/wato/ospf_neighbor.py    | 193 +++++++++++++++++++++++++++++++++++
 ospf_neighbor.mkp            | Bin 6583 -> 8370 bytes
 packages/ospf_neighbor       |  11 +-
 5 files changed, 270 insertions(+), 7 deletions(-)
 create mode 100644 gui/metrics/ospf_neighbor.py
 create mode 100644 gui/wato/ospf_neighbor.py

diff --git a/CHANGELOG b/CHANGELOG
index 9233d00..bf1ca91 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,4 +3,6 @@
             moved part of the output to long output
             a little code cleanup to better match coding guide lines
 2019-11-03: moved 'events' from infotext to longoutput
-2020-07-26: added parse section, alias, wato for alias, not found and state
\ No newline at end of file
+2020-07-26: added parse section, alias, wato for alias, not found and state
+2021-09-15: rewritten for CMK 2.0
+2023-04-22: moved wato/metrics file to ~/local/lib/check_mk/gui/plugins/(wato|metrics)
diff --git a/gui/metrics/ospf_neighbor.py b/gui/metrics/ospf_neighbor.py
new file mode 100644
index 0000000..89f3284
--- /dev/null
+++ b/gui/metrics/ospf_neighbor.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# OSPF neighbor metrics plugin
+#
+# Author: Th.L.
+# Date  : 2018-06-15
+#
+# metrics plugin for ospf_neighbor check
+#
+# 2023-04-22: moved to ~/local/lib/check_mk/gui/plugins/metrics
+
+from cmk.gui.i18n import _
+
+from cmk.gui.plugins.metrics.utils import (
+    metric_info,
+    graph_info,
+    perfometer_info
+)
+
+#####################################################################################################################
+#
+# define metrics for OSPF neighbor perfdata
+#
+#####################################################################################################################
+
+metric_info['ospf_neighbor_ospf_events'] = {
+    'title': _('Events'),
+    'unit': 'count',
+    'color': '16/a',
+}
+
+metric_info['ospf_neighbor_ospf_retransmission_queue_length'] = {
+    'title': _('Retransmission queue length'),
+    'unit': 'count',
+    'color': '36/a',
+}
+
+
+######################################################################################################################
+#
+# how to graph perdata for OSPF neighbor
+#
+######################################################################################################################
+
+graph_info['ospf_neighbor_ospf_events'] = {
+    'title': _('OSPF neighbor events'),
+    'metrics': [
+        ('ospf_neighbor_ospf_events', 'area'),
+    ],
+}
+
+graph_info['ospf_neighbor_ospf_retransmission_queue_length'] = {
+    'title': _('OSPF neighbor Retransmission queue length'),
+    'metrics': [
+        ('ospf_neighbor_ospf_retransmission_queue_length', 'area'),
+    ],
+}
+######################################################################################################################
+#
+# define perf-o-meter for OSPF neighbor events
+#
+######################################################################################################################
+
+perfometer_info.append({
+    'type': 'linear',
+    'segments': ['ospf_neighbor_ospf_events'],
+    # 'total': 100,
+})
diff --git a/gui/wato/ospf_neighbor.py b/gui/wato/ospf_neighbor.py
new file mode 100644
index 0000000..c753c6d
--- /dev/null
+++ b/gui/wato/ospf_neighbor.py
@@ -0,0 +1,193 @@
+#!/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  : 2020-07-26
+#
+# wato plugin for ospf_neighbor check
+#
+# 2023-04-22: moved to ~/local/lib/check_mk/gui/plugins/wato
+
+from cmk.gui.i18n import _
+from cmk.gui.valuespec import (
+    Dictionary,
+    TextAscii,
+    ListOf,
+    Tuple,
+    TextUnicode,
+    MonitoringState,
+)
+
+from cmk.gui.plugins.wato.utils import (
+    CheckParameterRulespecWithItem,
+    rulespec_registry,
+    RulespecGroupCheckParametersNetworking,
+)
+
+
+def _parameter_valuespec_ospf_neighbor():
+    return Dictionary(
+        elements=[
+            ('state_not_found',
+             MonitoringState(
+                 title=_('State to report if neighbor not found'),
+                 help=_('Default monitoring state if the neighbor not found in the SNMP data. Default monitoring '
+                        'state is "UNKNOWN"'),
+                 default_value=3,
+             )),
+            ('neighborstate',
+             Dictionary(
+                 title=_('State to report for OSPF neighbor state'),
+                 help=_('Map each OSPF state to a CheckMK monitoring state'),
+                 elements=[
+                     ('1',
+                      MonitoringState(
+                          title=_('1 - down'),
+                          help=_('This is the first OSPF neighbor state. It means that no information (hellos) has '
+                                 'been received from this neighbor, but hello packets can still be sent to the '
+                                 'neighbor in this state. During the fully adjacent neighbor state, if a router '
+                                 'doesn\'t receive hello packet from a neighbor within the RouterDeadInterval time '
+                                 '(RouterDeadInterval = 4*HelloInterval by default) or if the manually configured '
+                                 'neighbor is being removed from the configuration, then the neighbor state changes '
+                                 'from Full to Down. Default monitoring state is "CRIT"'),
+                          default_value=2,
+                      )),
+                     ('2',
+                      MonitoringState(
+                          title=_('2 - attempt'),
+                          help=_('This state is only valid for manually configured neighbors in an NBMA environment. '
+                                 'In Attempt state, the router sends unicast hello packets every poll interval to the '
+                                 'neighbor, from which hellos have not been received within the dead interval. '
+                                 'Default monitoring state is "WARN"'),
+                          default_value=1,
+                      )),
+                     ('3',
+                      MonitoringState(
+                          title=_('3 - init'),
+                          help=_('This state specifies that the router has received a hello packet from its neighbor, '
+                                 'but the receiving router\'s ID was not included in the hello packet. When a router '
+                                 'receives a hello packet from a neighbor, it should list the sender\'s router ID in '
+                                 'its hello packet as an acknowledgment that it received a valid hello packet. '
+                                 'Default monitoring state is "WARN"'),
+                          default_value=1,
+                      )),
+                     ('4',
+                      MonitoringState(
+                          title=_('4 - twoWay'),
+                          help=_('This state designates that bi-directional communication has been established between '
+                                 'two routers. Bi-directional means that each router has seen the other\'s hello '
+                                 'packet. This state is attained when the router receiving the hello packet sees its '
+                                 'own Router ID within the received hello packet\'s neighbor field. At this state, a '
+                                 'router decides whether to become adjacent with this neighbor. On broadcast media '
+                                 'and non-broadcast multiaccess networks, a router becomes full only with the '
+                                 'designated router (DR) and the backup designated router (BDR); it stays in the 2-way '
+                                 'state with all other neighbors. On Point-to-point and Point-to-multipoint networks, '
+                                 'a router becomes full with all connected routers. At the end of this stage, the DR '
+                                 'and BDR for broadcast and non-broadcast multiacess networks are elected. For more '
+                                 'information on the DR election process, refer to DR Election. Note: Receiving a '
+                                 'Database Descriptor (DBD) packet from a neighbor in the init state will also a cause '
+                                 'a transition to 2-way state. Default monitoring state is "OK"'),
+                          default_value=0,
+                      )),
+                     ('5',
+                      MonitoringState(
+                          title=_('5 - exchangeStart'),
+                          help=_('Once the DR and BDR are elected, the actual process of exchanging link state '
+                                 'information can start between the routers and their DR and BDR. In this state, '
+                                 'the routers and their DR and BDR establish a master-slave relationship and choose '
+                                 'the initial sequence number for adjacency formation. The router with the higher '
+                                 'router ID becomes the master and starts the exchange, and as such, is the only '
+                                 'router that can increment the sequence number. Note that one would logically '
+                                 'conclude that the DR/BDR with the highest router ID will become the master during '
+                                 'this process of master-slave relation. Remember that the DR/BDR election might be '
+                                 'purely by virtue of a higher priority configured on the router instead of highest '
+                                 'router ID. Thus, it is possible that a DR plays the role of slave. And also note '
+                                 'that master/slave election is on a per-neighbor basis. Default monitoring state '
+                                 'is "WARN"'),
+                          default_value=1,
+                      )),
+                     ('6',
+                      MonitoringState(
+                          title=_('6 - exchange'),
+                          help=_('In the exchange state, OSPF routers exchange database descriptor (DBD) packets. '
+                                 'Database descriptors contain link-state advertisement (LSA) headers only and '
+                                 'describe the contents of the entire link-state database. Each DBD packet has a '
+                                 'sequence number which can be incremented only by master which is explicitly '
+                                 'acknowledged by slave. Routers also send link-state request packets and link-state '
+                                 'update packets (which contain the entire LSA) in this state. The contents of the '
+                                 'DBD received are compared to the information contained in the routers link-state '
+                                 'database to check if new or more current link-state information is available with '
+                                 'the neighbor. Default monitoring state is "WARN"'),
+                          default_value=1,
+                      )),
+                     ('7',
+                      MonitoringState(
+                          title=_('7 - loading'),
+                          help=_('In this state, the actual exchange of link state information occurs. Based on the '
+                                 'information provided by the DBDs, routers send link-state request packets. The '
+                                 'neighbor then provides the requested link-state information in link-state update '
+                                 'packets. During the adjacency, if a router receives an outdated or missing LSA, it '
+                                 'requests that LSA by sending a link-state request packet. All link-state update '
+                                 'packets are acknowledged. Default monitoring state is "WARN"'),
+                          default_value=1,
+                      )),
+                     ('8',
+                      MonitoringState(
+                          title=_('8 - full'),
+                          help=_('In this state, routers are fully adjacent with each other. All the router and '
+                                 'network LSAs are exchanged and the routers databases are fully synchronized. Full '
+                                 'is the normal state for an OSPF router. If a router is stuck in another state, '
+                                 'it\'s an indication that there are problems in forming adjacencies. The only '
+                                 'exception to this is the 2-way state, which is normal in a broadcast network. '
+                                 'Routers achieve the full state with their DR and BDR only. Neighbors always see '
+                                 'each other as 2-way. Default monitoring state is "OK"'),
+                          default_value=0,
+                      )),
+                 ])
+             ),
+            ('peer_list',
+             ListOf(
+                 Tuple(
+                     title=_('OSPF Neighbors'),
+                     elements=[
+                         TextUnicode(
+                             title=_('OSPF Neighbor IP address'),
+                             help=_(
+                                 'The configured value must match a OSPF Neighbor item reported by the monitored '
+                                 'device. For example: "10.10.10.10"'),
+                             allow_empty=False,
+                         ),
+                         TextUnicode(
+                             title=_('OSPF Neighbor Alias'),
+                             help=_('You can configure an individual alias here for the OSPF Neighbor matching '
+                                    'the text configured in the "OSPF Neighbor IP address" field. The alias will '
+                                    'be shown in the check info (i.e. [your alias])'),
+                             allow_empty=False,
+                         ),
+                         MonitoringState(
+                             default_value=2,
+                             title=_('State if not found'),
+                             help=_('You can configure an individual state if the OSPF Neighbor matching the text '
+                                    'configured in the "OSPF Neighbor IP address" field is not found. '
+                                    'Default monitoring state is "CRIT".')
+                         )]),
+                 add_label=_('Add OSPF Neighbor'),
+                 movable=False,
+                 title=_('OSPF Neighbor specific configuration'),
+             )),
+        ],
+    )
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithItem(
+        check_group_name='ospf_neighbor',
+        group=RulespecGroupCheckParametersNetworking,
+        item_spec=lambda: TextAscii(title=_('OSPF Neighbor IP address'), ),
+        match_type='dict',
+        parameter_valuespec=_parameter_valuespec_ospf_neighbor,
+        title=lambda: _('OSPF neighbor'),
+    ))
diff --git a/ospf_neighbor.mkp b/ospf_neighbor.mkp
index 7aca821f4ec77c2f67345be861844e29d7f6c6d1..d66109502dde67873ce8ef22389f17dbf9f3040a 100644
GIT binary patch
literal 8370
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
Sm#9=IJWo?mKg=}@%>MxWNmF_N

literal 6583
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

diff --git a/packages/ospf_neighbor b/packages/ospf_neighbor
index 0895b1a..cf443fa 100644
--- a/packages/ospf_neighbor
+++ b/packages/ospf_neighbor
@@ -8,16 +8,15 @@
                 '            moved part of the output to long output\n'
                 '2020-07-26: added parse section, alias, wato for alias and '
                 'state\n'
-                '2021-09-15: rewritten for CMK 2.0\n',
+                '2021-09-15: rewritten for CMK 2.0\n'
+                '2023-04-22: moved wato/metrics to new structure\n',
  'download_url': 'https://thl-cmk.hopto.org',
  'files': {'agent_based': ['ospf_neighbor.py'],
            'checkman': ['ospf_neighbor'],
-           'web': ['plugins/metrics/ospf_neighbor.py',
-                   'plugins/wato/ospf_neighbor.py']},
+           'gui': ['metrics/ospf_neighbor.py', 'wato/ospf_neighbor.py']},
  'name': 'ospf_neighbor',
- 'num_files': 4,
  'title': 'OSPF Neighbor State Check',
- 'version': '20210915.v1.4a',
- 'version.min_required': '2.0.0',
+ 'version': '1.4.1-20230422',
+ 'version.min_required': '2.1.0b1',
  'version.packaged': '2.1.0p21',
  'version.usable_until': None}
\ No newline at end of file
-- 
GitLab