From ff58f68ae9e1d7c59b6b83ba222c9f7852d63153 Mon Sep 17 00:00:00 2001 From: "th.l" <thl-cmk@outlook.com> Date: Tue, 17 Jan 2023 20:59:08 +0100 Subject: [PATCH] update project --- agent_based/arista_bgp_peer.py | 144 +++++++++++++++++++++++++++ agent_based/inv_arista_bgp_peer.py | 119 ++++++++++++++++++++++ agent_based/utils/arista_bgp_peer.py | 41 ++++++++ arista_bgp_peer.mkp | Bin 0 -> 3180 bytes packages/arista_bgp_peer | 27 +++++ 5 files changed, 331 insertions(+) create mode 100644 agent_based/arista_bgp_peer.py create mode 100644 agent_based/inv_arista_bgp_peer.py create mode 100644 agent_based/utils/arista_bgp_peer.py create mode 100644 arista_bgp_peer.mkp create mode 100644 packages/arista_bgp_peer diff --git a/agent_based/arista_bgp_peer.py b/agent_based/arista_bgp_peer.py new file mode 100644 index 0000000..9570c4b --- /dev/null +++ b/agent_based/arista_bgp_peer.py @@ -0,0 +1,144 @@ +#!/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 : 2023-01-16 +# +# Monitor status of Arista Networks BGP Peers (IPv4 and IPv6) +# +# +# + +import copy +from typing import List, Dict, Optional, Tuple +from dataclasses import dataclass + +from cmk.base.plugins.agent_based.agent_based_api.v1 import ( + register, + SNMPTree, + startswith, + 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 ( + BgpPeer, + bgp_get_peer_entry, + bgp_get_ip_address_from_oid, +) + +from cmk.base.plugins.agent_based.utils.arista_bgp_peer import ( + arista_afi_safi_mapping, +) + + +@dataclass +class AristaPrefixes: + afi: str + safi: str + accepted_prefixes: int + metric_count: List[Tuple[str, int]] + metric_rate: List[Tuple[str, int]] + + +def parse_arista_bgp_peer(string_table: List[StringByteTable]) -> Optional[Dict[str, BgpPeer]]: + BgpPeerTable, BgpPrefixCountersTable = string_table + + peer_table = {} + peer_prefixes = {} + + for entry in BgpPrefixCountersTable: + oid_end, in_prefixes, in_prefixes_accepted, out_prefixes = entry + oid_end_split = oid_end.split('.') + afi = oid_end_split[-2] + safi = oid_end_split[-1] + index = '.'.join(oid_end_split[:-2]) + prefixes = AristaPrefixes( + afi=afi, + safi=safi, + accepted_prefixes=int(in_prefixes_accepted), + metric_rate=[], + metric_count=[ + ('in_prefixes', int(in_prefixes)), + ('out_prefixes', int(out_prefixes)), + ], + ) + + if peer_prefixes.get(index): + peer_prefixes[index].append(prefixes) + else: + peer_prefixes[index] = [prefixes] + + for entry in BgpPeerTable: + oid_end, remote_as, remote_id, admin_state, peer_state, in_updates, out_updates, in_messages, out_messages, \ + fsm_established_transitions, fsm_established_time, in_update_elapsed_time = entry + + remote_addr = bgp_get_ip_address_from_oid(f'{oid_end[2:]}') + + bgp_peer = bgp_get_peer_entry( + remote_addr=remote_addr, + peer_state=peer_state, + admin_state=admin_state, + remote_as=remote_as, + in_updates=in_updates, + out_updates=out_updates, + in_messages=in_messages, + out_messages=out_messages, + fsm_established_transitions=fsm_established_transitions, + fsm_established_time=fsm_established_time, + in_update_elapsed_time=in_update_elapsed_time + ) + + prefixes = peer_prefixes.get(oid_end, []) + for address_family in prefixes: + address_family_str = arista_afi_safi_mapping(address_family.afi, address_family.safi) + item = f'{remote_addr} {address_family_str}' + peer_table[item] = copy.deepcopy(bgp_peer[remote_addr]) + peer_table[item].accepted_prefixes = address_family.accepted_prefixes + peer_table[item].metric_count += address_family.metric_count + peer_table[item].metric_rate += address_family.metric_rate + peer_table[item].item['address_family'] = address_family_str + peer_table[item].item['routing_instance'] = '' + return peer_table + + +register.snmp_section( + name='arista_bgp_peer', + parse_function=parse_arista_bgp_peer, + parsed_section_name='bgp_peer', + supersedes=['bgp_peer', 'arista_bgp'], + fetch=[ + SNMPTree( + base='.1.3.6.1.4.1.30065.4.1.1', # AARISTA-BGP4V2-MIB::aristaBgp4V2Objects + oids=[ + OIDEnd(), + '2.1.10', # aristaBgp4V2PeerRemoteAs + OIDBytes('2.1.11'), # aristaBgp4V2PeerRemoteIdentifier + '2.1.12', # aristaBgp4V2PeerAdminStatus + '2.1.13', # aristaBgp4V2PeerState + '7.1.1', # aristaBgp4V2PeerInUpdates + '7.1.2', # aristaBgp4V2PeerOutUpdates + '7.1.3', # aristaBgp4V2PeerInTotalMessages + '7.1.4', # aristaBgp4V2PeerOutTotalMessages + '7.1.5', # aristaBgp4V2PeerFsmEstablishedTransitions + '4.1.1', # aristaBgp4V2PeerFsmEstablishedTime + '4.1.2', # aristaBgp4V2PeerInUpdatesElapsedTime + ]), + SNMPTree( + base='.1.3.6.1.4.1.30065.4.1.1.8.1', # ARISTA-BGP4V2-MIB::aristaBgp4V2PrefixGaugesEntry + oids=[ + OIDEnd(), # index.afi.safi + '3', # aristaBgp4V2PrefixInPrefixes + '4', # aristaBgp4V2PrefixInPrefixesAccepted + '5', # aristaBgp4V2PrefixOutPrefixes + ] + ), + ], + detect=startswith('.1.3.6.1.2.1.1.2.0', '.1.3.6.1.4.1.30065'), # ARISTA-SMI-MIB::arista +), diff --git a/agent_based/inv_arista_bgp_peer.py b/agent_based/inv_arista_bgp_peer.py new file mode 100644 index 0000000..b6380f9 --- /dev/null +++ b/agent_based/inv_arista_bgp_peer.py @@ -0,0 +1,119 @@ +#!/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 : 2023-01-17 +# +# inventory of Arista Networks BGP Peers (IPv4 and IPv6) +# +# + + +from typing import List +from cmk.base.plugins.agent_based.agent_based_api.v1 import ( + register, + SNMPTree, + OIDBytes, + startswith, + OIDEnd, +) +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_error_code_as_hex, + bgp_render_ip_address, + get_bgp_type, + bgp_get_ip_address_from_oid, +) +from cmk.base.plugins.agent_based.utils.arista_bgp_peer import ( + arista_afi_safi_mapping, +) + + +def parse_inv_arista_bgp_peer(string_table: List[StringByteTable]): + peers, address_families = string_table + + bgp_peers = [] + + peer_families = {} + for entry in address_families: + oid_end, in_prefixes = entry + oid_end_split = oid_end.split('.') + afi = oid_end_split[-2] + safi = oid_end_split[-1] + index = '.'.join(oid_end_split[:-2]) + + if peer_families.get(index): + peer_families[index] = peer_families[index] + [arista_afi_safi_mapping(afi, safi)] + else: + peer_families[index] = [arista_afi_safi_mapping(afi, safi)] + + for entry in peers: + oid_end, local_addr_type, local_addr, local_as, local_id, remote_as, remote_id, state, last_error_received, \ + fsm_established_time, fsm_established_trans = entry + + remote_addr = bgp_get_ip_address_from_oid(f'{oid_end[2:]}') + + # assuming IPv4 address format + local_id = bgp_render_ip_address('1', local_id) + remote_id = bgp_render_ip_address('1', remote_id) + + bgp_peer: InvBgpPeer = { + 'remote_addr': remote_addr, + '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_received), + 'last_error': bgp_error_as_string(last_error_received), + 'status_columns': {}, + 'address_family': ', '.join(peer_families.get(oid_end, [])) + } + bgp_peers.append(bgp_peer) + + return bgp_peers + + +register.snmp_section( + name='inv_arista_bgp_peer', + parse_function=parse_inv_arista_bgp_peer, + parsed_section_name='inv_bgp_peer', + supersedes=['inv_bgp_peer'], + fetch=[ + SNMPTree( + base='.1.3.6.1.4.1.30065.4.1.1', # AARISTA-BGP4V2-MIB::aristaBgp4V2Objects + oids=[ + OIDEnd(), + '2.1.2', # aristaBgp4V2PeerLocalAddrType + OIDBytes('2.1.3'), # aristaBgp4V2PeerLocalAddr + '2.1.7', # aristaBgp4V2PeerLocalAs + OIDBytes('2.1.8'), # aristaBgp4V2PeerLocalIdentifier + '2.1.10', # aristaBgp4V2PeerRemoteAs + OIDBytes('2.1.11'), # aristaBgp4V2PeerRemoteIdentifier + '2.1.13', # aristaBgp4V2PeerState + OIDBytes('3.1.1'), # aristaBgp4V2PeerLastErrorCodeReceived + '4.1.1', # aristaBgp4V2PeerFsmEstablishedTime + '7.1.5', # aristaBgp4V2PeerFsmEstablishedTransitions + ] + ), + SNMPTree( + base='.1.3.6.1.4.1.30065.4.1.1.8.1', # ARISTA-BGP4V2-MIB::aristaBgp4V2PrefixGaugesEntry + oids=[ + OIDEnd(), # index.addr-type.addr_length.addr.afi[-2].safi[-1] + '3', # aristaBgp4V2PrefixInPrefixes + ] + ), + ], + detect=startswith('.1.3.6.1.2.1.1.2.0', '.1.3.6.1.4.1.30065'), # ARISTA-SMI-MIB::arista +), diff --git a/agent_based/utils/arista_bgp_peer.py b/agent_based/utils/arista_bgp_peer.py new file mode 100644 index 0000000..ac76ea6 --- /dev/null +++ b/agent_based/utils/arista_bgp_peer.py @@ -0,0 +1,41 @@ +#!/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 : 2023-01-16 +# +# include file, will be used with arista_bgp_peer and inv_arista_bgp_peer +# +# + +def arista_address_type(st: str): + names = { + '0': 'unknown', + '1': 'ipv4', + '2': 'ipv6', + } + return names.get(st, st) + + +def arista_address_family(st: str): + names = { + '0': 'unknown', + '1': 'ipv4', + '2': 'ipv6', + } + return names.get(st, st) + + +def arista_afi_safi_mapping(afi: str, safi: str) -> str: + names = { + (1, 1): 'IPv4 unicast', + (1, 2): 'IPv4 multicast', + (2, 1): 'IPv6 unicast', + (2, 2): 'IPv6 multicast', + (1, 4): 'MPLS IPv4', + (2, 4): 'MPLS IPv6', + } + return names.get((int(afi), int(safi)), f'AFI {afi} SAFI {safi}') diff --git a/arista_bgp_peer.mkp b/arista_bgp_peer.mkp new file mode 100644 index 0000000000000000000000000000000000000000..1908d9891cb3b68929da876be0815e96e0e4c532 GIT binary patch literal 3180 zcmbWp`6Cky0{~!mOs-VUwUFg~G3VSy$XQ6qO^&$@bCZpi+!@UsBSr3;MLFiqHRYb% z$`N61v3>u;_x$vLl9`zSlzwMAsw2`PAkfjl$<5Ef4-Q94%1X=1Nz2G6LV~3s(lQVq zFF%@HfqBHdiY$==KwR97Fe$cda1LP$t>5x6<|@iAGC1vnGCVAHhBkb-Rnqhz9lgZ2 zt!t1`Q0fy7@MBlV9BfU?7ay>evV0Yx!52q^J;<T5j$h8mf5fUgtL5<yOl*xypT_l% z^FBTu^xI>(3r__0n4x;XeWO?4ee=c%7hpdr#XZ~Ws@eGBD@h|zL6KF}D$Zjyer2?q z4O_yEU?M%hxI^H^I}a0inDmdq*T39L;ZsgjS27}JfeU-i;?j9)$G$3;$V_N3S!3ii zvFvwl+%FB*;$xvV<bCa{9{<Lim)ld->jv#-k@+C!AzrIF0b-}f2Xrt>6@0@rc=-k$ z7W*K+DxtqC-1*wwo@U2g`{lE8BR5-414oQNxMp!q%@?UU@Vvi!hUsaPeqSqI-dK(4 z5J-O0JfQEQs(1nwHRiq7!b4+G_=*9(^qq#CoT`Hg-(}>`Xu|J7Ox%<Mj16HC9VV85 zzcEv$ImP!<)N|@1odTd%7BlJI+?WjDn~ZOy8-Kbpyt`T(b_p<Uf$64Jk-M|21M~mb zDNH!rH|TZM(`yad{w-~&rJhoYscG-U*QVw}gAfXedVWa=UQl?nkw|E)ocg~y>}@A~ zqbiqzXYY2cJ$ByP?cK})u0ILF*)nZ3lV1)+v4qY*CA!)g9&qe;jPuWi2gWlj6h&KE zE<MTs<A|yET!tfT?O*tcA)d4x-CeNkBkL)pbs?04|151ziz-;E4X;Hh%j;?P<ZR=$ zBi$1kFZx-lawt;APAEWLIlUp9NC-gD&1JI(z2yoNg`Z@aRLe)T(~@kMIZq=19o%Yz z)QkJKnK~g<fdQ<)2vwlpub525u2ZihsC&dg%Ad<lwC2gHBa9A*Ar%xea6eck8Er9C z^K--3xE~aw_i^ra@_@^*;DO#x0)}>`B<;{N7c&wzn6z<ynU=}CL@m@|2S35NI(*1K z7ARU9sc-KB3gCg5H!$GJ{c6(7{UAhPB^#4x-7b<Q{*OkU3Tvg8A{D~&ZpidXFj_v? z{`+ZDxV(FO(>Jr30lvk{TnM9p4mZLt6(9GQ9#9RAmXM8w6=-J_oGbMXXhRRqJJ2Ib z<-m+`ZK4C!_+TXzmbuS{>Prj%;k_t|uiU6ghE^{Fe=_RHe-ix$yh%?eJ53R!aGM2h zh7*ocK78HYS57^`5k|ZQf6&IH{N3KYMowaqj|&XJ*`MQ{j-=aQ-{ba4bXZpl16qC1 zVrQJ{a7rK;)D^~3LcjWA2PViL-yeHOOy;0dd1NLg`Fz1V!SwOI6W!KICk~(3trT6Y z8`5qrh|ov!5K0YT6#iLYS~iXzy>w7K5Eq5Y)rF0Y*E9RSd@CcSfXqXdWxrc?mG0iQ zVs~rf4SeM`oT_#;EjD{}eoLx!rjCK%ji)0S?>i>tY}lwMzYrUF@+Rnn@@MC#$8r`? z>QB+4$|l>LW&m(3+8Sb4e-RFO!<%}|%E75r`-Eee7|>>aTMn8kRU<NK+TyL#TFRo= z7zOL7#6+ZLW+&b@Y}O)Pm5R!*+C_?<e`qI5#Gw^}V_Uiyk0?*eGpVDGchzd;-T2}& z73rIMbHhD-ABuY3YTmlO{Uz4KM@+E7Sy?E9O%8!%ML4n+scTmKH0w<!@U@MHtDEv= zG@GU?3|GR|DjIK0+88g5|3YfAQ|(CSbfYk5+;8{R{KS8UC89bH)UOf+XdKqoT#R+1 z)r|+I^42FD_A2WeUTpNd%y(cPr+eWAly!ykFznEb^z}K5g-zL4ZG&lq^fLzF@_bej z<aP$v!;pf`Q>dLlMp@A!KuE+=FmD)%GvG=A(0Uz8MbX+Go4n&W`dudX;<*9$b6flu zRP`+e*^T|qa5S@ptXuU;mcbYy;i5rXV3LJVJ6|g6yE0<r@L}cSsTl?ezoN~P)fawu zg}9(u6A9Xng&iNp*awj++sd~%O)hL1W2|0(iECcwH3DkUx|cd6N&Hhr+(d+rlZtt* zgJ(llp4_NR-2y-AdT({k?9YK{3Uwx|$6MHE<Z1M{^S6dBj8(P2j80_hHBLxAe{_6O zpV8(dkSu#-hN&i~yqRUsiI<@rx5i#}*a4c#eDx$iQU#SRc02T1N{<jM+gF(<(50*H ze91lNgLL>l&glEY1p$VzfR*#2YAF;lV1@HH&aB|bRxPMpTA_B*T)S*imPh`XHdhmr z2RgI<bkhgo+0<9wTT$K?*Ya@g&?m00fJF=qX})<LHd*Bg0cEu|adOYs*r^b;5{fqi zORC|K;QfxWtX}bw<j^AjrcbH-?;P}|Wu_H)Hxo3<K$=>LUEJPw(qj?iX32AVueTD! z_pIyDD~#fn3nlX1@u(FM*60IdU1t2E;k8c-{VjQ7^U6uBQJ3FV!NwX1T;O~JOzCq0 z8^z8&$kS(zRBAryt;*ZC{M>SRA7!^}I%YUQZc{f{(=3YpURCxp=(e|T@{?<J|FBxl zPUj7y(jIJm$+Ib;9Vj$PR;8VgRI=flV8S;zeEr4hXnYCPALian0*_e_uJrA`zvEp0 z1?ScF4s*nE30&j0J;R)1Y4cfZ8B7)n?QC&^-9g@$4u|`rbIEfO*lUR#x{G#^|3PP} zSuV2;00}#9CbB14@)GIdb9K^HU8hffa2V&LfI7vF<&fF}-tRPeU=?_>`wyXo3?mIf zzCXdY92hI2EcAU`;cJr$3EXG3FEq@DtVm_-Fv3>5yoWeuJ39UKB~J=}1coHNq&cY1 zKa*-vu0{^SGjm9`{R?hW%fha?{H?8PWhRYkqVT$#62~&^A2g&2+&^=`Poph@0d8T| zpC{CM-<r}$nacznJez_6a=HB8xe;0=KrS2jx10Bf|N5-1L7b%Tln-trGeHq|hHUdR zqjD{PSX9vR59+d%E_)(BIV!D?()U*GU^C+GuT#pE#fjX=(-U<3#8%S|HFd?u*F9x` z`{^;-oQnTURsDHcS?JN(dOZJo`-HNN^O?$Cm?m6psn73u&EXjF)isi@*QDdbYcqqc z^0;3Zg$lJy9~nV!t#M4$`%#Id`?{EkPX*VS(P-2ue!Id@_*aZdWn;tKSAIop%u*9+ z^!tD6V~{K@dh?>8h_YsTGwk^ZWNWFDp0vGuOJIJHAYNC&o*#I|(XjbtVoemcM9Th5 ziu7^hSS3BbWARDH8MQeJQ>2VY#zvEKZ<*M;4NLoSUMLtL2U5zl+iiA|eYa@H;KC;0 z5jOm#>7h&(LR!I%@cB%ES%XrZ$JiGf@Sr;M`%GOhq>gD6`bSve+r5Q>Tu#PsTwV(A zSmKLD_1%6y5f^=CiJR}@f;9*#!Y(KO6_4^bH*T>U)9m1X%i`sVOiVD#E4UuxTP{DK zqRaJzRy*bRYADrcYgBaT(bF}Jl4JPO$K(nEs}7UyO^Vhp&KNNNDZ<G$g#DBom6jRH zaDB{*zT%dyvi}g<lS{*qlYNWwe&uJzadT1@rsBX8(Xm<E;8$jAX0G$``-8XH-&_T9 z@7H4Y1bAQf^Uey`CxqG}2JGtFt(B)EhfORGCJfGxtxUYrGTk}0Fb2rImOHr&kw%5r z>+#1!o`)Krv`;=rHl!l@y#hP9rK64f`hY$SPxP{@)`haw7QkT^UVqLNa#aNaI$I>q z9xt>T9wp4{4YUx}Ouns9V@=7h({s?`)y1FNwv|GMe~$=VDI7AA2lt0R5`r3j5od*a zRI>43J&$+Z+rT?3e5a1<cezi{DT(Q)Xx;Y*lY-7vH_r+RW}CWmNs*$S6)xkauFY+n zS=`j931PVacr2dQGv50L&=ALIe~_$dW6yk0oFRHCQgfM<*i2VB^_RpcULyaArJERS zTG+!z*WbSRT!I9Z1Ld#BoI1($<{oYXI#pZ@zJ<9<h*uIR#;n*M{^un23e57^NBF+) zjOX8eS{bG~Ce)G<Ju#Z$z69sSC=!LeFktPeQhMYfIFi((Ge+x@!nHPf{+ktb;GH%D z4#|H8+PfDzN`zUiDxyN|J?^6m(rfpFO(16?W6M7+t~$Tn6f-T-jHY7*{GYi5CB%j| J(uC5`{0~#6Got_i literal 0 HcmV?d00001 diff --git a/packages/arista_bgp_peer b/packages/arista_bgp_peer new file mode 100644 index 0000000..9aaf4ed --- /dev/null +++ b/packages/arista_bgp_peer @@ -0,0 +1,27 @@ +{'author': 'Th.L. (thl-cmk[at]outlook[dot]com)', + 'description': 'Monitors Arista Networks BGP Peers.\n' + '\n' + '- creates one service for each peer/address family (IPv4 ' + 'and IPv6)\n' + '- performance data include: peer uptime, prefixes accepted, ' + 'advertised,\n' + '- this package contains also a inventory plugin\n' + '\n' + 'NOTE: this plugin will supersede the original arista_bgp ' + 'plugin\n' + '\n' + 'NOTE: to use this plugin you must also install my bgp_peer ' + 'plugin ' + '(https://thl-cmk.hopto.org/gitlab/checkmk/vendor-independent/bgp_peer)\n' + '\n', + 'download_url': 'https://thl-cmk.hopto.org/gitlab/arista/arista_bgp_peer', + 'files': {'agent_based': ['arista_bgp_peer.py', + 'inv_arista_bgp_peer.py', + 'utils/arista_bgp_peer.py']}, + 'name': 'arista_bgp_peer', + 'num_files': 3, + 'title': 'Arista BGP peer', + 'version': '20230117.v0.01', + 'version.min_required': '2.0.0', + 'version.packaged': '2021.09.20', + 'version.usable_until': None} \ No newline at end of file -- GitLab