From 5c658ad530463c27fb10c76fa31ae29d957d4999 Mon Sep 17 00:00:00 2001
From: "th.l" <thl-cmk@outlook.com>
Date: Sun, 1 May 2022 18:13:56 +0200
Subject: [PATCH] update project

---
 agent_based/cisco_bgp_peer.py     | 212 ++++++++----------------------
 agent_based/inv_cisco_bgp_peer.py | 135 +++++++++++++++++++
 cisco_bgp_peer.mkp                | Bin 5328 -> 5523 bytes
 packages/cisco_bgp_peer           |   6 +-
 4 files changed, 194 insertions(+), 159 deletions(-)
 create mode 100644 agent_based/inv_cisco_bgp_peer.py

diff --git a/agent_based/cisco_bgp_peer.py b/agent_based/cisco_bgp_peer.py
index 794b3f8..7aeb676 100644
--- a/agent_based/cisco_bgp_peer.py
+++ b/agent_based/cisco_bgp_peer.py
@@ -48,8 +48,13 @@
 # 2021-11-14: merged check function with bgp_peer
 #             merged parse function with bgp_peer
 #             added basic support for VRFs (cbgpPeer3Entry)
+# 2022.04.22: moved inventory plugin to inv_cisco_bgp_peer.py
+# 2022-04-29: added info if device is admin prefix limit capable (device_admin_limit)
+# 2022-04-30: code cleanup/streamlining
+#
 
-from typing import List, Dict, Optional
+from typing import List, Dict, Optional, Tuple
+from dataclasses import dataclass
 
 from cmk.base.plugins.agent_based.agent_based_api.v1 import (
     register,
@@ -66,11 +71,7 @@ from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
 )
 
 from cmk.base.plugins.agent_based.utils.bgp_peer import (
-    bgp_peerstate,
-    bgp_errors,
-    bgp_render_ip_address,
-    bgp_get_peer,
-    ByteToHex,
+    bgp_get_ip_address_from_oid,
     BgpPeer,
     bgp_get_peer_entry,
 )
@@ -80,35 +81,38 @@ from cmk.base.plugins.agent_based.utils.bgp_peer import (
 #  cisco_bgp_peer (CISCO-BGP4-MIB:cbgpPeer2Entry)
 #
 ###########################################################################
+@dataclass
+class CiscoPrefixes:
+    address_family: str
+    metric_count: List[Tuple[str, int]]
+    metric_rate: List[Tuple[str, int]]
+    accepted_prefixes: Optional[int]
+    prefix_admin_limit: Optional[int]
+    prefix_clear_threshold: Optional[int]
+    prefix_threshold: Optional[int]
 
 
 def parse_cisco_bgp_peer(string_table: List[StringTable]) -> Dict[str, BgpPeer]:
     cbgpPeer2Entry, cbgpPeer2AddrFamily = string_table
 
-    # create dictionary from cbgpPeer2Entry (peer ip address as index)
     peer_table = {}
-    for entry in cbgpPeer2Entry:
-        entry[0] = bgp_get_peer(entry[0])  # replace OID_END with remote address
-        bgp_peer = bgp_get_peer_entry(entry)
-        if bgp_peer:
-            peer_table.update(bgp_peer)
-
-    prefixes_table = {}
-    # create dictionary from cbgpPeer2AddrFamily (with 'remoteip addrfamilyname' as index)
+    peer_prefixes = {}
+    # create dictionary by peer address and list of entries per address family
     for entry in cbgpPeer2AddrFamily:
         oid_end, addrfamilyname, acceptedprefixes, deniedprefixes, prefixadminlimit, prefixthreshold, \
         prefixclearthreshold, advertisedprefixes, suppressedprefixes, withdrawnprefixes = entry
 
         if not oid_end == '':
-
-            remoteaddr = bgp_get_peer(oid_end)
-            # merge peer info with prefixes
-            prefixes = peer_table[remoteaddr]
-            prefixes.prefix_admin_limit = int(prefixadminlimit) if prefixadminlimit.isdigit() else None
-            prefixes.accepted_prefixes = int(acceptedprefixes) if acceptedprefixes.isdigit() else None
-            prefixes.prefix_clear_threshold = int(prefixclearthreshold) if prefixclearthreshold.isdigit() else None
-            prefixes.prefix_threshold = int(prefixthreshold) if prefixthreshold.isdigit() else None
-
+            remote_addr = bgp_get_ip_address_from_oid(oid_end)
+            prefixes = CiscoPrefixes(
+                address_family=addrfamilyname,
+                metric_count=[],
+                metric_rate=[],
+                accepted_prefixes=int(acceptedprefixes) if acceptedprefixes.isdigit() else None,
+                prefix_admin_limit=int(prefixadminlimit) if prefixadminlimit.isdigit() else None,
+                prefix_clear_threshold=int(prefixthreshold) if prefixthreshold.isdigit() else None,
+                prefix_threshold=int(prefixthreshold) if prefixthreshold.isdigit() else None
+            )
             for key, value in [
                 ('advertisedprefixes', advertisedprefixes),
                 ('deniedprefixes', deniedprefixes),
@@ -120,20 +124,34 @@ def parse_cisco_bgp_peer(string_table: List[StringTable]) -> Dict[str, BgpPeer]:
                 except ValueError:
                     pass
 
-            prefixes_table.update({f'{remoteaddr} {addrfamilyname}': prefixes})
+            if peer_prefixes.get(remote_addr):
+                peer_prefixes[remote_addr].append(prefixes)
+            else:
+                peer_prefixes[remote_addr] = [prefixes]
+
+    # create dictionary from cbgpPeer2Entry (peer ip address as index)
+    peer_table: Dict[str, BgpPeer] = {}
+    for entry in cbgpPeer2Entry:
+        remote_address = bgp_get_ip_address_from_oid(entry[0])
+        entry[0] = remote_address  # replace OID_END with remote address
+        bgp_peer = bgp_get_peer_entry(entry)
+        if bgp_peer:
+            prefixes = peer_prefixes.get(remote_address, [])
+            if prefixes:
+                for address_family in prefixes:
+                    item = f'{remote_address} {address_family.address_family}'
+                    peer_table[item] = bgp_peer[remote_address]
+                    peer_table[item].accepted_prefixes = address_family.accepted_prefixes
+                    peer_table[item].prefix_admin_limit = address_family.prefix_admin_limit
+                    peer_table[item].prefix_clear_threshold = address_family.prefix_clear_threshold
+                    peer_table[item].prefix_threshold = address_family.prefix_threshold
+                    peer_table[item].device_admin_limit = True
+                    peer_table[item].metric_rate += address_family.metric_count
+                    peer_table[item].metric_rate += address_family.metric_rate
+            else:
+                peer_table.update(bgp_peer)
 
-    if prefixes_table:
-        for peer in peer_table.keys():
-            no_address_family = False
-            for address_family in prefixes_table.keys():
-                if address_family.startswith(peer):
-                    no_address_family = True
-                    break
-            if not no_address_family:
-                prefixes_table.update({peer:peer_table[peer]})
-        return prefixes_table
-    else:
-        return peer_table
+    return peer_table
 
 
 register.snmp_section(
@@ -188,7 +206,7 @@ register.snmp_section(
 ###########################################################################
 
 
-# ToDo: add support for non ipv6, needs sample
+# ToDo: add support for non IPv4, needs sample
 def parse_cisco_bgp_peer_3(string_table: StringByteTable) -> Optional[Dict[str, BgpPeer]]:
     peer_table = {}
     for entry in string_table:
@@ -257,121 +275,3 @@ register.snmp_section(
 # '30',  # cbgpPeer3LastErrorTxt
 # '31',  # cbgpPeer3PrevState
 
-###########################################################################
-#
-#  INVENTORY Plugin inv_cisco_bgp_peer (CISCO-BGP4-MIB::cbgpPeer2Entry)
-#
-###########################################################################
-
-
-def parse_inv_cisco_bgp_peer(string_table: List[StringTable]):
-    peers, address_family, base = string_table
-
-    bgp_peers = []
-
-    # convert families from list to dict
-    # [
-    #  ['1.4.77.235.182.229.1.1', 'IPv4 Unicast'],
-    #  ['1.4.217.119.208.2.1.1', 'IPv4 Unicast'],
-    #  ['1.4.217.119.208.34.1.1', 'IPv4 Unicast'],
-    #  ['2.16.42.0.28.160.16.0.1.53.0.0.0.0.0.0.0.1.2.1', 'IPv6 Unicast'],
-    #  ['2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.17.2.1', 'IPv6 Unicast']
-    # ]
-    #
-    # {
-    #  '1.4.77.235.182.229.1.1': 'IPv4 Unicast',
-    #  '1.4.217.119.208.2.1.1': 'IPv4 Unicast',
-    #  '1.4.217.119.208.34.1.1': 'IPv4 Unicast',
-    #  '2.16.42.0.28.160.16.0.1.53.0.0.0.0.0.0.0.1.2.1': 'IPv6 Unicast',
-    #  '2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.17.2.1': 'IPv6 Unicast'
-    # }
-    peer_families = dict(map(lambda x: (x[0], x[1]), address_family))
-
-    for entry in peers:
-        try:
-            oid_end, local_addr, local_as, local_id, remote_as, remote_id, last_error, last_errortxt, \
-            prev_state = entry
-        except ValueError:
-            return
-
-        if local_as == '0':
-            try:
-                local_as = base[0][0]
-            except (ValueError, IndexError):
-                local_as = 'N/A'
-
-        address_families = []
-        for key in peer_families:
-            if key.startswith(oid_end):
-                address_families.append(peer_families[key])
-
-        peer = {
-            'remote_addr': bgp_get_peer(oid_end),
-            'remote_id': remote_id,
-            'version': '4',
-            'local_addr': bgp_render_ip_address(local_addr),
-            'remote_as': remote_as,
-            'local_as': local_as,
-            'local_id': local_id,
-            'status_columns': {
-                'last_error_code': ByteToHex(last_error),
-                'last_error': bgp_errors(last_error),
-                'prev_state': bgp_peerstate(prev_state),
-            },
-        }
-
-        if local_as.isdigit():
-            if local_as == remote_as:
-                peer['bgp_type'] = 'iBGP'
-            else:
-                peer['bgp_type'] = 'eBGP'
-        else:
-            peer['bgp_type'] = 'N/A'
-
-        if address_families:
-            peer['address_family'] = ','.join(address_families)
-
-        bgp_peers.append(peer)
-
-    return bgp_peers
-
-
-register.snmp_section(
-    name='inv_cisco_bgp_peer',
-    parse_function=parse_inv_cisco_bgp_peer,
-    parsed_section_name='inv_bgp_peer',
-    supersedes=['inv_bgp_peer'],
-    fetch=[
-        SNMPTree(
-            base='.1.3.6.1.4.1.9.9.187.1.2.5.1',  # CISCO-BGP4-MIB::cbgpPeer2Entry
-            oids=[
-                OIDEnd(),
-                '6',  # cbgpPeer2LocalAddr
-                '8',  # cbgpPeer2LocalAs -> empty
-                '9',  # cbgpPeer2LocalIdentifier
-                '11',  # cbgpPeer2RemoteAs
-                '12',  # cbgpPeer2RemoteIdentifier
-                '17',  # cbgpPeer2LastError
-                '28',  # cbgpPeer2LastErrorTxt
-                '29',  # cbgpPeer2PrevState
-            ]
-        ),
-        SNMPTree(
-            base='.1.3.6.1.4.1.9.9.187.1.2',  # cbgpPeer
-            oids=[
-                OIDEnd(),  #
-                '7.1.3',  # cbgpPeer2AddrFamilyName
-            ]
-        ),
-        SNMPTree(
-            base='.1.3.6.1.2.1.15',  # BGP-4-MIB
-            oids=[
-                '2',  # bgpLocalAs
-            ]
-        )
-    ],
-    detect=all_of(
-        contains('.1.3.6.1.2.1.1.1.0', 'Cisco'),
-        exists('.1.3.6.1.4.1.9.9.187.1.2.5.1.3.*')
-    ),
-)
diff --git a/agent_based/inv_cisco_bgp_peer.py b/agent_based/inv_cisco_bgp_peer.py
new file mode 100644
index 0000000..d13f459
--- /dev/null
+++ b/agent_based/inv_cisco_bgp_peer.py
@@ -0,0 +1,135 @@
+#!/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-04-22
+#
+# inventory of Cisco BGP Peers (IPv4 and IPv6)
+#
+# 2022-04-22: moved here from cisco_bgp_peer
+# 2022-04-30: code cleanup/streamlining
+#
+
+from typing import List
+from cmk.base.plugins.agent_based.agent_based_api.v1 import (
+    register,
+    SNMPTree,
+    exists,
+    contains,
+    all_of,
+    OIDEnd,
+    OIDBytes,
+)
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
+    StringByteTable
+)
+from cmk.base.plugins.agent_based.utils.bgp_peer import (
+    InvBgpPeer,
+    bgp_error_as_string,
+    bgp_render_ip_address,
+    bgp_get_ip_address_from_oid,
+    bgp_error_code_as_hex,
+    get_bgp_type,
+)
+
+
+def parse_inv_cisco_bgp_peer(string_table: List[StringByteTable]):
+    peers, address_family, base = string_table
+    try:
+        base_local_as = base[0][0]
+    except (ValueError, IndexError):
+        base_local_as = 'N/A'
+
+    bgp_peers = []
+
+    peer_families = dict(address_family)
+
+    for entry in peers:
+        try:
+            oid_end, state, local_addr, local_as, local_id, remote_as, remote_id, last_error, \
+            fsm_established_time, last_errortxt = entry
+        except ValueError:
+            return
+
+        if len(local_addr) == 4:
+            local_addr_type = '1'  # IPv4
+        elif len(local_addr) == 16:
+            local_addr_type = '2'  # IPv6
+        else:
+            local_addr_type = '0'
+
+        if local_as == '0':
+            local_as = base_local_as
+
+        address_families = []
+        for key in peer_families:
+            if key.startswith(oid_end):
+                address_families.append(peer_families[key])
+
+        bgp_peer: InvBgpPeer = {
+            'remote_addr': bgp_get_ip_address_from_oid(oid_end),
+            'remote_id': remote_id,
+            'version': '4',
+            'local_addr': bgp_render_ip_address(local_addr_type, local_addr),
+            'remote_as': remote_as,
+            'local_as': local_as,
+            'local_id': local_id,
+            'bgp_type': get_bgp_type(local_as, remote_as),
+            'fsm_established_time': int(fsm_established_time),
+            'peer_state': 1 if state == '6' else 2,  # adjust to match if_oper_status for inventory painter
+            'last_error_code': bgp_error_code_as_hex(last_error),
+            'last_error': bgp_error_as_string(last_error),
+            'status_columns': {},
+            'address_family': ','.join(address_families)
+        }
+
+        bgp_peers.append(bgp_peer)
+
+    return bgp_peers
+
+
+register.snmp_section(
+    name='inv_cisco_bgp_peer',
+    parse_function=parse_inv_cisco_bgp_peer,
+    parsed_section_name='inv_bgp_peer',
+    supersedes=['inv_bgp_peer'],
+    fetch=[
+        SNMPTree(
+            base='.1.3.6.1.4.1.9.9.187.1.2.5.1',  # CISCO-BGP4-MIB::cbgpPeer2Entry
+            oids=[
+                OIDEnd(),
+                '3',  # cbgpPeer2State
+                OIDBytes('6'),  # cbgpPeer2LocalAddr
+                '8',  # cbgpPeer2LocalAs -> empty
+                '9',  # cbgpPeer2LocalIdentifier
+                '11',  # cbgpPeer2RemoteAs
+                '12',  # cbgpPeer2RemoteIdentifier
+                OIDBytes('17'),  # cbgpPeer2LastError
+                '19',  # cbgpPeer2FsmEstablishedTime
+                '28',  # cbgpPeer2LastErrorTxt
+            ]
+        ),
+        SNMPTree(
+            base='.1.3.6.1.4.1.9.9.187.1.2',  # cbgpPeer
+            oids=[
+                OIDEnd(),  #
+                '7.1.3',  # cbgpPeer2AddrFamilyName
+            ]
+        ),
+        SNMPTree(
+            base='.1.3.6.1.2.1.15',  # BGP-4-MIB
+            oids=[
+                '2',  # bgpLocalAs
+            ]
+        )
+    ],
+    detect=all_of(
+        contains('.1.3.6.1.2.1.1.1.0', 'Cisco'),
+        exists('.1.3.6.1.4.1.9.9.187.1.2.5.1.3.*')
+    ),
+)
+
+
diff --git a/cisco_bgp_peer.mkp b/cisco_bgp_peer.mkp
index c942943cd31c75950e96fad95d0e1282fee88992..19858fe91a3c82956d309e90955c2de15c8de518 100644
GIT binary patch
literal 5523
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
J$11|Y`ac$9w;BKd

literal 5328
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
G0PsI0Cvs8%

diff --git a/packages/cisco_bgp_peer b/packages/cisco_bgp_peer
index 414d2e7..f44dd4f 100644
--- a/packages/cisco_bgp_peer
+++ b/packages/cisco_bgp_peer
@@ -21,12 +21,12 @@
                 'v0.5: merged with bgp_peer '
                 '(https://thl-cmk.hopto.org/gitlab/checkmk/vendor-independent/bgp_peer)\n',
  'download_url': 'https://thl-cmk.hopto.org',
- 'files': {'agent_based': ['cisco_bgp_peer.py'],
+ 'files': {'agent_based': ['cisco_bgp_peer.py', 'inv_cisco_bgp_peer.py'],
            'checkman': ['cisco_bgp_peer']},
  'name': 'cisco_bgp_peer',
- 'num_files': 2,
+ 'num_files': 3,
  'title': 'Cisco BGP Peer',
- 'version': '20211114.v.0.5',
+ 'version': '20220422.v.0.6',
  'version.min_required': '2.0.0',
  'version.packaged': '2021.09.20',
  'version.usable_until': None}
\ No newline at end of file
-- 
GitLab