From 960efb2b46088ed6be7c91f9b866c0976e40b983 Mon Sep 17 00:00:00 2001 From: Oleg Strizhechenko Date: Sun, 16 Jul 2017 01:15:53 +0500 Subject: [PATCH] Added: snmptop utility. (#142) * based on BaseTop interface * `--random` support * `--no-delta-mode` support * added to `tests_runnable` https://github.com/strizhechenko/netutils-linux/issues/143 --- netutils_linux_monitoring/layout.py | 6 +- netutils_linux_monitoring/snmptop.py | 89 ++++++++++++++++++++++++++++ setup.py | 2 +- tests/proc_net_snmp/snmp1 | 12 ++++ tests/proc_net_snmp/snmp2 | 12 ++++ tests/utils_runnable | 2 + utils/snmptop | 10 ++++ 7 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 netutils_linux_monitoring/snmptop.py create mode 100644 tests/proc_net_snmp/snmp1 create mode 100644 tests/proc_net_snmp/snmp2 create mode 100644 utils/snmptop diff --git a/netutils_linux_monitoring/layout.py b/netutils_linux_monitoring/layout.py index ac7a784..fc90102 100644 --- a/netutils_linux_monitoring/layout.py +++ b/netutils_linux_monitoring/layout.py @@ -10,7 +10,11 @@ def make_table(header, align_map=None, rows=None): """ Wrapper for pretty table """ table = PrettyTable() table.horizontal_char = table.vertical_char = table.junction_char = ' ' - table.field_names = header + try: + table.field_names = header + except Exception as err: + print_(header) + raise err if align_map: for field, align in zip(header, align_map): table.align[field] = align diff --git a/netutils_linux_monitoring/snmptop.py b/netutils_linux_monitoring/snmptop.py new file mode 100644 index 0000000..987cb6d --- /dev/null +++ b/netutils_linux_monitoring/snmptop.py @@ -0,0 +1,89 @@ +# coding=utf-8 + +from copy import deepcopy +from random import randint + +from six import iteritems + +from netutils_linux_monitoring.base_top import BaseTop +from netutils_linux_monitoring.layout import make_table + + +class SnmpTop(BaseTop): + """ Utility for monitoring IP/TCP/UDP/ICMP parts of network stack based on /proc/net/snmp values """ + + protos = ['IP', 'TCP', 'UDP', 'ICMP'] + + @staticmethod + def make_parser(parser=None): + """ :returns: parser with options for snmptop """ + if not parser: + parser = BaseTop.make_parser() + parser.add_argument('--snmp-file', default='/proc/net/snmp', + help='Option for testing on MacOS purpose.') + return parser + + def __int(self, line): + return [self.int(item) for item in line.strip().split()] + + def eval(self): + """ Evaluates difference between snmp metrics """ + self.diff = deepcopy(self.current) + for proto, data in iteritems(self.diff): + for i, metric in enumerate(data): + _, value = metric + if isinstance(value, int): + if self.options.random: + self.diff[proto][i][1] = randint(0, 1000) + else: + self.diff[proto][i][1] -= self.previous[proto][i][1] + + @staticmethod + def __listify(list_of_tuples): + """ + :param list_of_tuples: list[tuple] + :return: list[list] + """ + return [list(tpl) for tpl in list_of_tuples] + + def parse(self): + """ :returns: dict[proto] = list[list[str(key), int(value)]] """ + with open(self.options.snmp_file) as file_fd: + lines = [self.__int(line) for line in file_fd.readlines()] + return { + 'IP': self.__listify(zip(lines[0][1:], lines[1][1:])), + 'ICMP': self.__listify(zip(lines[2][1:], lines[3][1:])), + 'TCP': self.__listify(zip(lines[6][1:], lines[7][1:])), + 'UDP': self.__listify(zip(lines[8][1:], lines[9][1:])) + } + + def __repr__(self): + table = make_table(self.make_header(), self.make_align_map(), self.make_rows()) + return self.__repr_table__(table) + + @staticmethod + def make_header(): + """ :returns: header for prettytable output (provides unique invisible whitespace-headers) + + 6, 5, 4 spaces are for column blinking avoidance. + """ + return ['IP', ' ' * 6, 'TCP', ' ' * 5, 'UDP', ' ' * 4, 'ICMP', ''] + + def make_rows(self): + """ :returns: rows for prettytable output (filled with empty values) """ + rows = [] + repr_source = self.repr_source() + max_len = max(len(subdict) for subdict in repr_source.values()) + for index in range(max_len): + row = list() + for proto in self.protos: + if index >= len(repr_source[proto]): + row.extend(['', '']) + continue + row.extend([repr_source[proto][index][0], repr_source[proto][index][1]]) + rows.append(row) + return rows + + def make_align_map(self): + """ :returns: align map for prettytable output (key <-, value -> for each proto """ + return ['l', 'r'] * len(self.protos) diff --git a/setup.py b/setup.py index e624ef5..63d5aa7 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ def read(*paths): setuptools.setup( name='netutils-linux', - version='2.2.10', + version='2.3.0', author='Oleg Strizhechenko', author_email='oleg.strizhechenko@gmail.com', license='MIT', diff --git a/tests/proc_net_snmp/snmp1 b/tests/proc_net_snmp/snmp1 new file mode 100644 index 0000000..23ad903 --- /dev/null +++ b/tests/proc_net_snmp/snmp1 @@ -0,0 +1,12 @@ +Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates +Ip: 1 64 22199703066 64 0 3991292426 3 0 18205118253 20899686159 1183 0 5 5 0 5 8 0 16 +Icmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps +Icmp: 17864682 762911 13469164 11533 0 53 7 4361700 21720 7 0 0 0 27650690 0 23265781 52 0 0 0 23150 4361700 0 7 0 0 +IcmpMsg: InType0 InType3 InType4 InType5 InType8 InType11 InType13 OutType0 OutType3 OutType8 OutType11 OutType14 +IcmpMsg: 21720 13469164 53 7 4361700 11533 7 4361700 23265781 23150 52 7 +Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts +Tcp: 1 200 120000 -1 1144887168 1265503546 23608568 26172378 77 17669927663 16338441124 133674663 167169 53028318 +Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors +Udp: 494467706 14809371 76 319088 0 0 +UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors +UdpLite: 0 0 0 0 0 0 diff --git a/tests/proc_net_snmp/snmp2 b/tests/proc_net_snmp/snmp2 new file mode 100644 index 0000000..3a84e7b --- /dev/null +++ b/tests/proc_net_snmp/snmp2 @@ -0,0 +1,12 @@ +Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates +Ip: 1 64 22199717960 64 0 3991292567 3 0 18205133002 20899699894 1183 0 5 5 0 5 8 0 16 +Icmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps +Icmp: 17864706 762912 13469188 11533 0 53 7 4361700 21720 7 0 0 0 27650753 0 23265844 52 0 0 0 23150 4361700 0 7 0 0 +IcmpMsg: InType0 InType3 InType4 InType5 InType8 InType11 InType13 OutType0 OutType3 OutType8 OutType11 OutType14 +IcmpMsg: 21720 13469188 53 7 4361700 11533 7 4361700 23265844 23150 52 7 +Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts +Tcp: 1 200 120000 -1 1144887961 1265504683 23608597 26172379 79 17669942271 16338454400 133674769 167169 53028393 +Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors +Udp: 494467738 14809443 76 319088 0 0 +UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors +UdpLite: 0 0 0 0 0 0 diff --git a/tests/utils_runnable b/tests/utils_runnable index 932d7d5..5ee5c8a 100755 --- a/tests/utils_runnable +++ b/tests/utils_runnable @@ -6,6 +6,7 @@ softirq="./tests/softirqs/i7/softirqs1" irq="./tests/interrupts/singlequeue_8cpu/interrupts_short" soft_net_stat="./tests/softnet_stat/softnet_stat1" devices="eth1,eth2,eth3" +snmp="./tests/proc_net_snmp/snmp1" network-top --no-clear -n 1 --random \ --softirqs-file="$softirq" \ @@ -16,6 +17,7 @@ link-rate --no-clear -n 1 --random --devices="$devices" irqtop --no-clear -n 1 --random --interrupts-file="$irq" softirq-top --no-clear -n 1 --random --softirqs-file="$softirq" softnet-stat-top --no-clear -n 1 --random --softnet-stat-file="$soft_net_stat" +snmptop --no-clear -n 1 --random --snmp-file="$snmp" autorps --help autoxps --help rss-ladder --help diff --git a/utils/snmptop b/utils/snmptop new file mode 100644 index 0000000..fdbc987 --- /dev/null +++ b/utils/snmptop @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +# coding: utf-8 + +from netutils_linux_monitoring.snmptop import SnmpTop + +if __name__ == '__main__': + top = SnmpTop() + top.options = top.make_parser().parse_args() + top.run()