From c20bd8d489c45401db55cf89bf7d4d0f7623a4fe Mon Sep 17 00:00:00 2001 From: Jan Jansky Date: Thu, 6 Feb 2020 08:56:11 +0100 Subject: [PATCH] [networking] options to limit namespaces * Added posibility to define namespaces with parameter namespaces = "". Posible regexp like "eth* ens4". * Added inspect_namespaces which defines how many namespaces should be inspected, by default unlimited * Added ethtool_namespaces variable which is by default true and if set to false it will not execute ethtool commands for namespaces * Changed options for OpenStack environment where ethtool_namespaces=False and inspect_namespaces = 200 Closes: #1916 Signed-off-by: Jan Jansky Signed-off-by: Pavel Moravec --- --- a/sos/plugins/networking.py +++ b/sos/plugins/networking.py @@ -9,7 +9,7 @@ from sos.plugins import (Plugin, RedHatPlugin, UbuntuPlugin, DebianPlugin, SoSPredicate) from os import listdir -import re +from re import match class Networking(Plugin): @@ -18,10 +18,17 @@ plugin_name = "networking" profiles = ('network', 'hardware', 'system') trace_host = "www.example.com" - option_list = [( + option_list = [ ("traceroute", "collect a traceroute to %s" % trace_host, "slow", - False) - )] + False), + ("namespace_pattern", "Specific namespaces pattern to be " + + "collected, namespaces pattern should be separated by whitespace " + + "as for example \"eth* ens2\"", "fast", ""), + ("namespaces", "Number of namespaces to collect, 0 for unlimited. " + + "Incompatible with the namespace_pattern plugin option", "slow", 0), + ("ethtool_namespaces", "Define if ethtool commands should be " + + "collected for namespaces", "slow", True) + ] # switch to enable netstat "wide" (non-truncated) output mode ns_wide = "-W" @@ -209,8 +216,41 @@ # per-namespace. ip_netns_file = self.get_cmd_output_now("ip netns") cmd_prefix = "ip netns exec " + # Regex initialization outside of for loop if ip_netns_file: - for namespace in self.get_ip_netns(ip_netns_file): + if self.get_option("namespace_pattern"): + pattern = '(?:%s$)' % '$|'.join( + self.get_option("namespace_pattern").split() + ).replace('*', '.*') + out_ns = [] + with open(ip_netns_file, 'r') as file: + ip_netns = file.read() + for line in ip_netns.splitlines(): + # If there's no namespaces, no need to continue + if line.startswith("Object \"netns\" is unknown") \ + or line.isspace() \ + or line[:1].isspace(): + continue + + # if namespace_pattern defined, append only namespaces + # matching with pattern + if self.get_option("namespace_pattern"): + if bool(match(pattern, line)): + out_ns.append(line.partition(' ')[0]) + + # if namespaces is defined and namespace_pattern is not defined + # remove from out_ns namespaces with higher index than defined + elif self.get_option("namespaces") != 0: + out_ns.append(line.partition(' ')[0]) + if len(out_ns) == self.get_option("namespaces"): + self._log_warn("Limiting namespace iteration " + + "to first %s namespaces found" + % self.get_option("namespaces")) + break + else: + out_ns.append(line.partition(' ')[0]) + + for namespace in out_ns: ns_cmd_prefix = cmd_prefix + namespace + " " self.add_cmd_output([ ns_cmd_prefix + "ip address show", @@ -227,24 +267,27 @@ # check for it self.add_cmd_output(ss_cmd, pred=ss_pred) - # Devices that exist in a namespace use less ethtool - # parameters. Run this per namespace. - for namespace in self.get_ip_netns(ip_netns_file): - ns_cmd_prefix = cmd_prefix + namespace + " " - netns_netdev_list = self.call_ext_prog(ns_cmd_prefix + + # Collect ethtool commands only when ethtool_namespaces + # is set to true. + if self.get_option("ethtool_namespaces"): + # Devices that exist in a namespace use less ethtool + # parameters. Run this per namespace. + for namespace in out_ns: + ns_cmd_prefix = cmd_prefix + namespace + " " + netns_netdev_list = self.call_ext_prog(ns_cmd_prefix + "ls -1 /sys/class/net/") - for eth in netns_netdev_list['output'].splitlines(): - # skip 'bonding_masters' file created when loading the - # bonding module but the file does not correspond to - # a device - if eth == "bonding_masters": - continue - self.add_cmd_output([ - ns_cmd_prefix + "ethtool " + eth, - ns_cmd_prefix + "ethtool -i " + eth, - ns_cmd_prefix + "ethtool -k " + eth, - ns_cmd_prefix + "ethtool -S " + eth - ]) + for eth in netns_netdev_list['output'].splitlines(): + # skip 'bonding_masters' file created when loading the + # bonding module but the file does not correspond to + # a device + if eth == "bonding_masters": + continue + self.add_cmd_output([ + ns_cmd_prefix + "ethtool " + eth, + ns_cmd_prefix + "ethtool -i " + eth, + ns_cmd_prefix + "ethtool -k " + eth, + ns_cmd_prefix + "ethtool -S " + eth + ]) return --- a/sos/policies/redhat.py +++ b/sos/policies/redhat.py @@ -174,8 +174,6 @@ _opts_verify = SoSOptions(verify=True) _opts_all_logs = SoSOptions(all_logs=True) _opts_all_logs_verify = SoSOptions(all_logs=True, verify=True) -_opts_all_logs_no_lsof = SoSOptions(all_logs=True, - plugopts=['process.lsof=off']) _cb_plugs = ['abrt', 'block', 'boot', 'dnf', 'dracut', 'filesys', 'grub2', 'hardware', 'host', 'kernel', 'logs', 'lvm2', 'memory', 'rpm', 'process', 'systemd', 'yum', 'xfs'] @@ -190,6 +188,10 @@ RHOSP = "rhosp" RHOSP_DESC = "Red Hat OpenStack Platform" +RHOSP_OPTS = SoSOptions(plugopts=[ + 'process.lsof=off', + 'networking.ethtool_namespaces=False', + 'networking.namespaces=200']) RHOCP = "ocp" RHOCP_DESC = "OpenShift Container Platform by Red Hat" @@ -211,8 +213,7 @@ RHV: PresetDefaults(name=RHV, desc=RHV_DESC, note=NOTE_TIME, opts=_opts_verify), RHEL: PresetDefaults(name=RHEL, desc=RHEL_DESC), - RHOSP: PresetDefaults(name=RHOSP, desc=RHOSP_DESC, note=NOTE_SIZE, - opts=_opts_all_logs_no_lsof), + RHOSP: PresetDefaults(name=RHOSP, desc=RHOSP_DESC, opts=RHOSP_OPTS), RHOCP: PresetDefaults(name=RHOCP, desc=RHOCP_DESC, note=NOTE_SIZE_TIME, opts=_opts_all_logs_verify), RH_SATELLITE: PresetDefaults(name=RH_SATELLITE, desc=RH_SATELLITE_DESC,