From 3bb79488029fd2a47da9c83678b4113b4786ef3e Mon Sep 17 00:00:00 2001
From: Thl CMK <thl-cmk@outlook.com>
Date: Sun, 26 Jul 2020 22:06:01 +0200
Subject: [PATCH] update project

---
 checkman/ospf_neighbor            |   7 +-
 checks/ospf_neighbor              | 234 +++++++++++++++++++-----------
 ospf_neighbor.mkp                 | Bin 5724 -> 7266 bytes
 packages/ospf_neighbor            |  11 +-
 web/plugins/wato/ospf_neighbor.py | 107 ++++++++++++++
 5 files changed, 270 insertions(+), 89 deletions(-)
 create mode 100644 web/plugins/wato/ospf_neighbor.py

diff --git a/checkman/ospf_neighbor b/checkman/ospf_neighbor
index 7acad47..69a62ab 100644
--- a/checkman/ospf_neighbor
+++ b/checkman/ospf_neighbor
@@ -46,9 +46,10 @@ description:
 
  {NbrOptions:}
  A BIT Mask corresponding to the neighbors options field. 
- Bit 0, if set, indicates that the area accepts and operates on external information; of zero, it is a stub area.
- Bit 1, if set, indicates that the system will operate on Type of Service metrics other than TOS 0.
- If zero, the neighbor will ignore all metrics except the TOS 0 metric.
+ Bit 0, if set, indicates that the area accepts and operates on external information; ff zero, it is a stub area.
+ Bit 1, if set, indicates that the system will operate on Type of Service metrics other than TOS 0. If zero, the neighbor will ignore all metrics except the TOS 0 metric.
+ Bit 2, if set, indicates that the system is capable of routing IP multicast datagrams, that is that it implements the multicast extensions to OSPF.
+ Bit 3, if set, indicates that the associated area is an NSSA.These areas are capable of carrying type-7 external advertisements, which are translated into type-5 external advertisements at NSSA borders.
 
  {NbrPriority:}
  The priority of this neighbor in the designated router election algorithm. The value 0 signifies that the neighbor is not eligible to becom the designated router on this particular network.
diff --git a/checks/ospf_neighbor b/checks/ospf_neighbor
index fed32f8..7ba6415 100644
--- a/checks/ospf_neighbor
+++ b/checks/ospf_neighbor
@@ -27,11 +27,17 @@
 # Author: Thomas Wollner (tw@wollner-net.de)
 ###############################################################################
 #
-# Th.L. 15-06-2018: changed item from neighbor id to neighbor ip
-#                   added events as perfdata (incl. metrics file)
-#                   moved part of the output to long output
-#                   a little code cleanup to better match coding guide lines
-#       03-11-2019: moved 'events' from infotext to longoutput
+# changes by: thl-cmk[at]outlook[dot]com
+# url       : https://thl-cmk.hopto.org
+#
+#  2018-06-15: changed item from neighbor id to neighbor ip
+#              added events as perfdata (incl. metrics file)
+#              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 and state
+#
+#
 #
 ###############################################################################
 
@@ -49,34 +55,27 @@
 # 1.3.6.1.2.1.14.10.1.9.172.20.2.214.0 = INTEGER: 1
 # 1.3.6.1.2.1.14.10.1.10.172.20.2.214.0 = INTEGER: 1
 # 1.3.6.1.2.1.14.10.1.11.172.20.2.214.0 = INTEGER: 2
-
+#
+# sample parsed
+# {
+#  '172.17.108.52': {'helperage': '', 'prio': '1', 'permanence': 'dynamic', 'helperstatus': '', 'options': '2',
+#                    'state': '8', 'hellosup': 'false', 'helperexitreason': '', 'events': 6, 'rtrid': '10.250.128.130'},
+#  '172.17.108.60': {'helperage': '', 'prio': '1', 'permanence': 'dynamic', 'helperstatus': '', 'options': '2',
+#                    'state': '8', 'hellosup': 'false', 'helperexitreason': '', 'events': 6, 'rtrid': '10.253.128.101'},
+#  '172.17.108.58': {'helperage': '', 'prio': '1', 'permanence': 'dynamic', 'helperstatus': '', 'options': '2',
+#                    'state': '8', 'hellosup': 'false', 'helperexitreason': '', 'events': 12, 'rtrid': '172.17.0.2'},
+#  '172.17.108.49': {'helperage': '', 'prio': '1', 'permanence': 'dynamic', 'helperstatus': '', 'options': '2',
+#                    'state': '8', 'hellosup': 'false', 'helperexitreason': '', 'events': 9, 'rtrid': '172.17.0.2'}
+# }
+#
 
 factory_settings['ospf_neighbor_default_levels'] = {
-    'ok_states'      : [8, 4],
-    'warning_states' : [2, 3, 5, 6, 7],
-    'critical_states': [1],
 }
 
-
-def inventory_ospf_neighbor(info):
-    inventory = []
-
-    for id, ip, rtrid, options, prio, state, events, permanence, \
-     hellosup, helperstatus, helperage, helperexitreason in info:
-        inventory.append((ip, {}))
-    return inventory
-
-
-def check_ospf_neighbor(item, params, info):
-    def ospf_nbr_state(st):
-        names = {'1': 'down',
-                 '2': 'attempt',
-                 '3': 'init',
-                 '4': 'twoWay',
-                 '5': 'exchangeStart',
-                 '6': 'exchange',
-                 '7': 'loading',
-                 '8': 'full'}
+def parse_ospf_neighbor(info):
+    def ospf_nbr_hellosuppressed(st):
+        names = {'1': 'true',
+                 '2': 'false'}
         return names.get(st, st)
 
     def ospf_nbr_permanence(st):
@@ -84,11 +83,6 @@ def check_ospf_neighbor(item, params, info):
                  '2': 'permanent'}
         return names.get(st, st)
 
-    def ospf_nbr_hellosuppressed(st):
-        names = {'1': 'true',
-                 '2': 'false'}
-        return names.get(st, st)
-
     def ospf_nbr_helperstatus(st):
         names = {'1': 'notHelping',
                  '2': 'helping'}
@@ -102,63 +96,138 @@ def check_ospf_neighbor(item, params, info):
                  '5': 'topologyChanged'}
         return names.get(st, st)
 
-    for id, ip, rtrid, options, prio, state, events, permanence, \
-     hellosupp, helperstatus, helperage, helperexitreason in info:
-
-        if ip == item:
-            nbrstatus = ospf_nbr_state(str(state))
-
-            output = 'Neighbor ID: %s' % rtrid
-            perfdata = []
-            longoutput = ''
-
-            nbrstate = int(state)
-                    
-            if nbrstate in params['critical_states']:
-                yield 2, 'State: %s' % nbrstatus
-            elif nbrstate in params['warning_states']:
-                yield 1, 'State: %s' % nbrstatus
-            elif nbrstate in params['ok_states']:
-                output += ', State: %s' % nbrstatus
-            else:
-                yield 3, 'Invalid Output from Agent'
-
-            if events:
-                events = int(events)
-                longoutput += '\nEvents: %d' % events
-                perfdata.append(['ospf_events', events])
-
-            if options:
-                longoutput += '\nNeighbor options: %s' % options
-            if prio:
-                longoutput += '\nNeighbor priority: %s' % prio
-            if permanence:
-                permanencestr = ospf_nbr_permanence(str(permanence))
-                longoutput += '\nNeighbor permanence: %s' % permanencestr
-            if hellosupp:
-                hellosuppstr = ospf_nbr_hellosuppressed(str(hellosupp))
-                longoutput += '\nNeighbor hello suppressed: %s' % hellosuppstr
-            if helperstatus:
-                helperstatusstr = ospf_nbr_helperstatus(str(helperstatus))
-                longoutput += '\nNeighbor helper status: %s' % helperstatusstr
-            if helperage:
-                longoutput += '\nNeighbor helper age: %s' % helperage
-            if helperexitreason:
-                helperexitreasonstr = ospf_nbr_helperexitreason(helperexitreason)
-                longoutput += '\nNeighbor helper exit reason: %s' % helperexitreasonstr
-            
-            yield 0, output + longoutput, perfdata
+    def ospf_nbr_options(st):
+        '''
+        A bit mask corresponding to the neighbor's options field.
+        Bit 0, if set, indicates that the system will operate on Type of Service metrics other than TOS 0.
+               If zero, the neighbor will ignore all metrics except the TOS 0 metric.
+        Bit 1, if set, indicates that the associated area accepts and operates on external information;
+               if zero, it is a stub area.
+        Bit 2, if set, indicates that the system is capable of routing IP multicast datagrams, that is that it
+               implements the multicast extensions to OSPF.
+        Bit 3, if set, indicates that the associated area is an NSSA. These areas are capable of carrying type-7
+               external advertisements, which are translated into type-5 external advertisements at NSSA borders.
+        '''
+        try:
+            st = ord(st)
+        except TypeError:
+            return 'unknown'
+
+        options = []
+        for key, value in [
+            (1, 'non TOS 0 service metrics accepted'),
+            (2, 'not a stub area'),
+            (4, 'IP multicast routing capable'),
+            (8, 'is NSSA'),
+        ]:
+            if st & key == key:
+                options.append(value)
+
+        options = ', '.join(options)
+        if options == '':
+            return 'unknown'
+        else:
+            return options
+
+    parsed = {}
+    for ip, rtrid, options, prio, state, events, permanence, hellosup, helperstatus, helperage, helperexitreason in info:
+        parsed[ip]={}
+        parsed[ip]['rtrid'] = rtrid
+        parsed[ip]['options'] = ospf_nbr_options(options)
+        parsed[ip]['prio'] = prio
+        parsed[ip]['state'] = state
+        parsed[ip]['events'] = int(events)
+        parsed[ip]['permanence'] = ospf_nbr_permanence(str(permanence))
+        parsed[ip]['hellosup'] = ospf_nbr_hellosuppressed(hellosup)
+        parsed[ip]['helperstatus'] = ospf_nbr_helperstatus(helperstatus)
+        parsed[ip]['helperage'] = helperage
+        parsed[ip]['helperexitreason'] = ospf_nbr_helperexitreason(helperexitreason)
+
+    return parsed
+
+
+def inventory_ospf_neighbor(parsed):
+    for neighbor in parsed.keys():
+        yield  neighbor, None
+
+
+def check_ospf_neighbor(item, params, parsed):
+    def ospf_nbr_state(st):
+        names = {'1': 'down',
+                 '2': 'attempt',
+                 '3': 'init',
+                 '4': 'twoWay',
+                 '5': 'exchangeStart',
+                 '6': 'exchange',
+                 '7': 'loading',
+                 '8': 'full'}
+        return names.get(st, 'unknown: %s' % st)
+
+    # default checkmk states for ctsxSxpConnStatus
+    neighborstate = {
+        '1': 2,  # down
+        '2': 1,  # attempt
+        '3': 1,  # init
+        '4': 0,  # twoWay
+        '5': 1,  # exchangeStart
+        '6': 1,  # exchange
+        '7': 1,  # loading
+        '8': 0,  # full
+    }
+
+    alias = None
+    notFoundState = 3
+
+    for neighbour, neighbourAlias, neighbourNotFoundState in params.get('peer_list', []):
+        if item == neighbour:
+            alias = neighbourAlias
+            notFoundState = neighbourNotFoundState
+
+    if item in parsed.keys():
+        neighbor = parsed[item]
+
+        perfdata = []
+        longoutput = ''
+
+        infotext = 'Neighbor ID: %s' % neighbor['rtrid']
+        if alias:
+            infotext += ', Alias: %s' % alias
+
+        neighborstate.update(params.get('neighborstate', neighborstate))  # update neighborstatus with params
+        yield neighborstate.get(neighbor['state'], 3), 'Status %s' % ospf_nbr_state(neighbor['state'])
+
+        perfdata.append(['ospf_events', neighbor['events']])
+
+        for text, value in [
+            ('\nNeighbor options', neighbor['options']),
+            ('\nNeighbor priority', neighbor['prio']),
+            ('\nNeighbor permanence', neighbor['permanence']),
+            ('\nNeighbor hello suppressed', neighbor['hellosup']),
+            ('\nNeighbor helper status', neighbor['helperstatus']),
+            ('\nNeighbor helper age', neighbor['helperage']),
+            ('\nNeighbor helper exit reason', neighbor['helperexitreason']),
+            ]:
+            if value != '':
+                longoutput += '%s: %s' %(text, value)
+
+        yield 0, infotext + longoutput, perfdata
+    else:
+        infotext = 'Item not found in SNMP data'
+        if alias:
+            infotext += ', Alias: %s' % alias
+        yield notFoundState, infotext
 
 
 check_info['ospf_neighbor'] = {
     'check_function'         : check_ospf_neighbor,
     'inventory_function'     : inventory_ospf_neighbor,
+    'parse_function'         : parse_ospf_neighbor,
     'service_description'    : 'OSPF neighbor %s',
     'default_levels_variable': 'ospf_neighbor_default_levels',
     'has_perfdata'           : True,
+    'group'                  : 'ospf_neighbor',
     'snmp_scan_function'     : lambda oid: oid('.1.3.6.1.2.1.14.10.1.1.*') != None,
     'snmp_info'              : ('.1.3.6.1.2.1.14.10.1', [
-                                OID_END,
                                 1,   # 'ospfNbrIpAddr'
                                 3,   # 'ospfNbrRtrId'
                                 4,   # 'ospfNbrOptions'
@@ -173,3 +242,6 @@ check_info['ospf_neighbor'] = {
                                 ]
                                 ),
  }
+
+
+
diff --git a/ospf_neighbor.mkp b/ospf_neighbor.mkp
index 4d52040a425801a39fc9d28a9275e4954f429a36..b3a155692273968a04519efaa6cbe033c063aa72 100644
GIT binary patch
literal 7266
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
b68~QU{@a27J1^85NYtdz0tCts3d(;0uoP4L

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

diff --git a/packages/ospf_neighbor b/packages/ospf_neighbor
index beeb97f..8b478bd 100644
--- a/packages/ospf_neighbor
+++ b/packages/ospf_neighbor
@@ -1,12 +1,13 @@
 {'author': u'Thomas Wollner',
- 'description': u'OSPF Neighborship State Check\n\nTh.L. 15-06-2018: changed item from neighbor id to neighbor address\n                  added events as perfdata (incl. metrics file)\n                  moved part of the output to long output\n',
+ 'description': u'OSPF Neighborship State Check\nchanges by thl-cmk[at]outlook[dot]com]\n2018-06-15: changed item from neighbor id to neighbor address\n            added events as perfdata (incl. metrics file)\n            moved part of the output to long output\n2020-07-26: added parse section, alias, wato for alias and state\n',
  'download_url': 'http://exchange.check-mk.org/',
  'files': {'checkman': ['ospf_neighbor'],
            'checks': ['ospf_neighbor'],
-           'web': ['plugins/metrics/ospf_neighbor.py']},
+           'web': ['plugins/metrics/ospf_neighbor.py',
+                   'plugins/wato/ospf_neighbor.py']},
  'name': 'ospf_neighbor',
- 'num_files': 3,
+ 'num_files': 4,
  'title': u'OSPF Neighbor State Check',
- 'version': '20191103.v1.2a',
+ 'version': '20200726.v1.3',
  'version.min_required': '1.2.8b8',
- 'version.packaged': '1.4.0p35'}
\ No newline at end of file
+ 'version.packaged': '1.4.0p38'}
\ No newline at end of file
diff --git a/web/plugins/wato/ospf_neighbor.py b/web/plugins/wato/ospf_neighbor.py
new file mode 100644
index 0000000..898e6c3
--- /dev/null
+++ b/web/plugins/wato/ospf_neighbor.py
@@ -0,0 +1,107 @@
+#!/usr/bin/python
+# -*- encoding: utf-8; py-indent-offset: 4 -*-
+#
+# 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
+#
+#
+
+register_check_parameters(
+    subgroup_networking,
+    'ospf_neighbor',
+    _('OSPF neighbor'),
+    Dictionary(
+        elements=[
+            ('neighborstate',
+             Dictionary(
+                 title=_('State to report for OSPF neighbor state'),
+                 elements=[
+                     ('1',
+                      MonitoringState(
+                          title=_('1 - down'),
+                          default_value=2,
+                      ),
+                      ),
+                     ('2',
+                      MonitoringState(
+                          title=_('2 - attempt'),
+                          default_value=1,
+                      ),
+                      ),
+                     ('3',
+                      MonitoringState(
+                          title=_('3 - init'),
+                          default_value=1,
+                      ),
+                      ),
+                     ('4',
+                      MonitoringState(
+                          title=_('4 - twoWay'),
+                          default_value=0,
+                      ),
+                      ),
+                     ('5',
+                      MonitoringState(
+                          title=_('5 - exchangeStart'),
+                          default_value=1,
+                      ),
+                      ),
+                     ('6',
+                      MonitoringState(
+                          title=_('6 - exchange'),
+                          default_value=1,
+                      ),
+                      ),
+                     ('7',
+                      MonitoringState(
+                          title=_('7 - loading'),
+                          default_value=1,
+                      ),
+                      ),
+                     ('8',
+                      MonitoringState(
+                          title=_('8 - full'),
+                          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 infotext'),
+                             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')
+                         )]),
+                 add_label=_('Add OSPF Neighbor'),
+                 movable=False,
+                 title=_('OSPF Neighbor specific configuration'),
+             )),
+        ],
+    ),
+    TextAscii(title=_('OSPF Neighbor IP address')),
+    match_type='dict',
+)
\ No newline at end of file
-- 
GitLab